Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2009  Red Hat, Inc.
      3  * Copyright  2011  Google, Inc.
      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  * Google Author(s): Behdad Esfahbod
     27  */
     28 
     29 #ifndef HB_FONT_HH
     30 #define HB_FONT_HH
     31 
     32 #include "hb.hh"
     33 
     34 #include "hb-face.hh"
     35 #include "hb-shaper.hh"
     36 
     37 
     38 /*
     39  * hb_font_funcs_t
     40  */
     41 
     42 #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
     43   HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
     44   HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
     45   HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
     46   HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \
     47   HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
     48   HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
     49   HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
     50   HB_FONT_FUNC_IMPLEMENT (glyph_h_advances) \
     51   HB_FONT_FUNC_IMPLEMENT (glyph_v_advances) \
     52   HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
     53   HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
     54   HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
     55   HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
     56   HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
     57   HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
     58   HB_FONT_FUNC_IMPLEMENT (glyph_name) \
     59   HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
     60   /* ^--- Add new callbacks here */
     61 
     62 struct hb_font_funcs_t
     63 {
     64   hb_object_header_t header;
     65 
     66   struct {
     67 #define HB_FONT_FUNC_IMPLEMENT(name) void *name;
     68     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
     69 #undef HB_FONT_FUNC_IMPLEMENT
     70   } user_data;
     71 
     72   struct {
     73 #define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
     74     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
     75 #undef HB_FONT_FUNC_IMPLEMENT
     76   } destroy;
     77 
     78   /* Don't access these directly.  Call font->get_*() instead. */
     79   union get_t {
     80     struct get_funcs_t {
     81 #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
     82       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
     83 #undef HB_FONT_FUNC_IMPLEMENT
     84     } f;
     85     void (*array[0
     86 #define HB_FONT_FUNC_IMPLEMENT(name) +1
     87       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
     88 #undef HB_FONT_FUNC_IMPLEMENT
     89 		]) ();
     90   } get;
     91 };
     92 DECLARE_NULL_INSTANCE (hb_font_funcs_t);
     93 
     94 
     95 /*
     96  * hb_font_t
     97  */
     98 
     99 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, font);
    100 #include "hb-shaper-list.hh"
    101 #undef HB_SHAPER_IMPLEMENT
    102 
    103 struct hb_font_t
    104 {
    105   hb_object_header_t header;
    106 
    107   hb_font_t *parent;
    108   hb_face_t *face;
    109 
    110   int x_scale;
    111   int y_scale;
    112 
    113   unsigned int x_ppem;
    114   unsigned int y_ppem;
    115 
    116   float ptem;
    117 
    118   /* Font variation coordinates. */
    119   unsigned int num_coords;
    120   int *coords;
    121 
    122   hb_font_funcs_t   *klass;
    123   void              *user_data;
    124   hb_destroy_func_t  destroy;
    125 
    126   hb_shaper_object_dataset_t<hb_font_t> data; /* Various shaper data. */
    127 
    128 
    129   /* Convert from font-space to user-space */
    130   int dir_scale (hb_direction_t direction)
    131   { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
    132   hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
    133   hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
    134   hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
    135   hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
    136   float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
    137   float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
    138   hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
    139   { return em_scale (v, dir_scale (direction)); }
    140 
    141   /* Convert from parent-font user-space to our user-space */
    142   hb_position_t parent_scale_x_distance (hb_position_t v)
    143   {
    144     if (unlikely (parent && parent->x_scale != x_scale))
    145       return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
    146     return v;
    147   }
    148   hb_position_t parent_scale_y_distance (hb_position_t v)
    149   {
    150     if (unlikely (parent && parent->y_scale != y_scale))
    151       return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
    152     return v;
    153   }
    154   hb_position_t parent_scale_x_position (hb_position_t v)
    155   { return parent_scale_x_distance (v); }
    156   hb_position_t parent_scale_y_position (hb_position_t v)
    157   { return parent_scale_y_distance (v); }
    158 
    159   void parent_scale_distance (hb_position_t *x, hb_position_t *y)
    160   {
    161     *x = parent_scale_x_distance (*x);
    162     *y = parent_scale_y_distance (*y);
    163   }
    164   void parent_scale_position (hb_position_t *x, hb_position_t *y)
    165   {
    166     *x = parent_scale_x_position (*x);
    167     *y = parent_scale_y_position (*y);
    168   }
    169 
    170 
    171   /* Public getters */
    172 
    173   HB_INTERNAL bool has_func (unsigned int i);
    174   HB_INTERNAL bool has_func_set (unsigned int i);
    175 
    176   /* has_* ... */
    177 #define HB_FONT_FUNC_IMPLEMENT(name) \
    178   bool \
    179   has_##name##_func () \
    180   { \
    181     hb_font_funcs_t *funcs = this->klass; \
    182     unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
    183     return has_func (i); \
    184   } \
    185   bool \
    186   has_##name##_func_set () \
    187   { \
    188     hb_font_funcs_t *funcs = this->klass; \
    189     unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
    190     return has_func_set (i); \
    191   }
    192   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
    193 #undef HB_FONT_FUNC_IMPLEMENT
    194 
    195   hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
    196   {
    197     memset (extents, 0, sizeof (*extents));
    198     return klass->get.f.font_h_extents (this, user_data,
    199 					extents,
    200 					klass->user_data.font_h_extents);
    201   }
    202   hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
    203   {
    204     memset (extents, 0, sizeof (*extents));
    205     return klass->get.f.font_v_extents (this, user_data,
    206 					extents,
    207 					klass->user_data.font_v_extents);
    208   }
    209 
    210   bool has_glyph (hb_codepoint_t unicode)
    211   {
    212     hb_codepoint_t glyph;
    213     return get_nominal_glyph (unicode, &glyph);
    214   }
    215 
    216   hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
    217 				      hb_codepoint_t *glyph)
    218   {
    219     *glyph = 0;
    220     return klass->get.f.nominal_glyph (this, user_data,
    221 				       unicode, glyph,
    222 				       klass->user_data.nominal_glyph);
    223   }
    224   unsigned int get_nominal_glyphs (unsigned int count,
    225 				   const hb_codepoint_t *first_unicode,
    226 				   unsigned int unicode_stride,
    227 				   hb_codepoint_t *first_glyph,
    228 				   unsigned int glyph_stride)
    229   {
    230     return klass->get.f.nominal_glyphs (this, user_data,
    231 					count,
    232 					first_unicode, unicode_stride,
    233 					first_glyph, glyph_stride,
    234 					klass->user_data.nominal_glyphs);
    235   }
    236 
    237   hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
    238 				 hb_codepoint_t *glyph)
    239   {
    240     *glyph = 0;
    241     return klass->get.f.variation_glyph (this, user_data,
    242 					 unicode, variation_selector, glyph,
    243 					 klass->user_data.variation_glyph);
    244   }
    245 
    246   hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
    247   {
    248     return klass->get.f.glyph_h_advance (this, user_data,
    249 					 glyph,
    250 					 klass->user_data.glyph_h_advance);
    251   }
    252 
    253   hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
    254   {
    255     return klass->get.f.glyph_v_advance (this, user_data,
    256 					 glyph,
    257 					 klass->user_data.glyph_v_advance);
    258   }
    259 
    260   void get_glyph_h_advances (unsigned int count,
    261 			     const hb_codepoint_t *first_glyph,
    262 			     unsigned int glyph_stride,
    263 			     hb_position_t *first_advance,
    264 			     unsigned int advance_stride)
    265   {
    266     return klass->get.f.glyph_h_advances (this, user_data,
    267 					  count,
    268 					  first_glyph, glyph_stride,
    269 					  first_advance, advance_stride,
    270 					  klass->user_data.glyph_h_advances);
    271   }
    272 
    273   void get_glyph_v_advances (unsigned int count,
    274 			     const hb_codepoint_t *first_glyph,
    275 			     unsigned int glyph_stride,
    276 			     hb_position_t *first_advance,
    277 			     unsigned int advance_stride)
    278   {
    279     return klass->get.f.glyph_v_advances (this, user_data,
    280 					  count,
    281 					  first_glyph, glyph_stride,
    282 					  first_advance, advance_stride,
    283 					  klass->user_data.glyph_v_advances);
    284   }
    285 
    286   hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
    287 				       hb_position_t *x, hb_position_t *y)
    288   {
    289     *x = *y = 0;
    290     return klass->get.f.glyph_h_origin (this, user_data,
    291 					glyph, x, y,
    292 					klass->user_data.glyph_h_origin);
    293   }
    294 
    295   hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
    296 				hb_position_t *x, hb_position_t *y)
    297   {
    298     *x = *y = 0;
    299     return klass->get.f.glyph_v_origin (this, user_data,
    300 					glyph, x, y,
    301 					klass->user_data.glyph_v_origin);
    302   }
    303 
    304   hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
    305 				     hb_codepoint_t right_glyph)
    306   {
    307     return klass->get.f.glyph_h_kerning (this, user_data,
    308 					 left_glyph, right_glyph,
    309 					 klass->user_data.glyph_h_kerning);
    310   }
    311 
    312   hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
    313 				     hb_codepoint_t bottom_glyph)
    314   {
    315     return klass->get.f.glyph_v_kerning (this, user_data,
    316 					 top_glyph, bottom_glyph,
    317 					 klass->user_data.glyph_v_kerning);
    318   }
    319 
    320   hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
    321 				      hb_glyph_extents_t *extents)
    322   {
    323     memset (extents, 0, sizeof (*extents));
    324     return klass->get.f.glyph_extents (this, user_data,
    325 				       glyph,
    326 				       extents,
    327 				       klass->user_data.glyph_extents);
    328   }
    329 
    330   hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
    331 					    hb_position_t *x, hb_position_t *y)
    332   {
    333     *x = *y = 0;
    334     return klass->get.f.glyph_contour_point (this, user_data,
    335 					     glyph, point_index,
    336 					     x, y,
    337 					     klass->user_data.glyph_contour_point);
    338   }
    339 
    340   hb_bool_t get_glyph_name (hb_codepoint_t glyph,
    341 			    char *name, unsigned int size)
    342   {
    343     if (size) *name = '\0';
    344     return klass->get.f.glyph_name (this, user_data,
    345 				    glyph,
    346 				    name, size,
    347 				    klass->user_data.glyph_name);
    348   }
    349 
    350   hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
    351 				 hb_codepoint_t *glyph)
    352   {
    353     *glyph = 0;
    354     if (len == -1) len = strlen (name);
    355     return klass->get.f.glyph_from_name (this, user_data,
    356 					 name, len,
    357 					 glyph,
    358 					 klass->user_data.glyph_from_name);
    359   }
    360 
    361 
    362   /* A bit higher-level, and with fallback */
    363 
    364   void get_h_extents_with_fallback (hb_font_extents_t *extents)
    365   {
    366     if (!get_font_h_extents (extents))
    367     {
    368       extents->ascender = y_scale * .8;
    369       extents->descender = extents->ascender - y_scale;
    370       extents->line_gap = 0;
    371     }
    372   }
    373   void get_v_extents_with_fallback (hb_font_extents_t *extents)
    374   {
    375     if (!get_font_v_extents (extents))
    376     {
    377       extents->ascender = x_scale / 2;
    378       extents->descender = extents->ascender - x_scale;
    379       extents->line_gap = 0;
    380     }
    381   }
    382 
    383   void get_extents_for_direction (hb_direction_t direction,
    384 				  hb_font_extents_t *extents)
    385   {
    386     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
    387       get_h_extents_with_fallback (extents);
    388     else
    389       get_v_extents_with_fallback (extents);
    390   }
    391 
    392   void get_glyph_advance_for_direction (hb_codepoint_t glyph,
    393 					hb_direction_t direction,
    394 					hb_position_t *x, hb_position_t *y)
    395   {
    396     *x = *y = 0;
    397     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
    398       *x = get_glyph_h_advance (glyph);
    399     else
    400       *y = get_glyph_v_advance (glyph);
    401   }
    402   void get_glyph_advances_for_direction (hb_direction_t direction,
    403 					 unsigned int count,
    404 					 const hb_codepoint_t *first_glyph,
    405 					 unsigned glyph_stride,
    406 					 hb_position_t *first_advance,
    407 					 unsigned advance_stride)
    408   {
    409     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
    410       get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
    411     else
    412       get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
    413   }
    414 
    415   void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
    416 				      hb_position_t *x, hb_position_t *y)
    417   {
    418     *x = get_glyph_h_advance (glyph) / 2;
    419 
    420     /* TODO cache this somehow?! */
    421     hb_font_extents_t extents;
    422     get_h_extents_with_fallback (&extents);
    423     *y = extents.ascender;
    424   }
    425 
    426   void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
    427 					 hb_position_t *x, hb_position_t *y)
    428   {
    429     if (!get_glyph_h_origin (glyph, x, y) &&
    430 	 get_glyph_v_origin (glyph, x, y))
    431     {
    432       hb_position_t dx, dy;
    433       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
    434       *x -= dx; *y -= dy;
    435     }
    436   }
    437   void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
    438 					 hb_position_t *x, hb_position_t *y)
    439   {
    440     if (!get_glyph_v_origin (glyph, x, y) &&
    441 	 get_glyph_h_origin (glyph, x, y))
    442     {
    443       hb_position_t dx, dy;
    444       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
    445       *x += dx; *y += dy;
    446     }
    447   }
    448 
    449   void get_glyph_origin_for_direction (hb_codepoint_t glyph,
    450 				       hb_direction_t direction,
    451 				       hb_position_t *x, hb_position_t *y)
    452   {
    453     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
    454       get_glyph_h_origin_with_fallback (glyph, x, y);
    455     else
    456       get_glyph_v_origin_with_fallback (glyph, x, y);
    457   }
    458 
    459   void add_glyph_h_origin (hb_codepoint_t glyph,
    460 			   hb_position_t *x, hb_position_t *y)
    461   {
    462     hb_position_t origin_x, origin_y;
    463 
    464     get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
    465 
    466     *x += origin_x;
    467     *y += origin_y;
    468   }
    469   void add_glyph_v_origin (hb_codepoint_t glyph,
    470 			   hb_position_t *x, hb_position_t *y)
    471   {
    472     hb_position_t origin_x, origin_y;
    473 
    474     get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
    475 
    476     *x += origin_x;
    477     *y += origin_y;
    478   }
    479   void add_glyph_origin_for_direction (hb_codepoint_t glyph,
    480 				       hb_direction_t direction,
    481 				       hb_position_t *x, hb_position_t *y)
    482   {
    483     hb_position_t origin_x, origin_y;
    484 
    485     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
    486 
    487     *x += origin_x;
    488     *y += origin_y;
    489   }
    490 
    491   void subtract_glyph_h_origin (hb_codepoint_t glyph,
    492 			        hb_position_t *x, hb_position_t *y)
    493   {
    494     hb_position_t origin_x, origin_y;
    495 
    496     get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
    497 
    498     *x -= origin_x;
    499     *y -= origin_y;
    500   }
    501   void subtract_glyph_v_origin (hb_codepoint_t glyph,
    502 				hb_position_t *x, hb_position_t *y)
    503   {
    504     hb_position_t origin_x, origin_y;
    505 
    506     get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
    507 
    508     *x -= origin_x;
    509     *y -= origin_y;
    510   }
    511   void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
    512 					    hb_direction_t direction,
    513 					    hb_position_t *x, hb_position_t *y)
    514   {
    515     hb_position_t origin_x, origin_y;
    516 
    517     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
    518 
    519     *x -= origin_x;
    520     *y -= origin_y;
    521   }
    522 
    523   void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
    524 					hb_direction_t direction,
    525 					hb_position_t *x, hb_position_t *y)
    526   {
    527     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
    528       *y = 0;
    529       *x = get_glyph_h_kerning (first_glyph, second_glyph);
    530     } else {
    531       *x = 0;
    532       *y = get_glyph_v_kerning (first_glyph, second_glyph);
    533     }
    534   }
    535 
    536   hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
    537 					  hb_direction_t direction,
    538 					  hb_glyph_extents_t *extents)
    539   {
    540     hb_bool_t ret = get_glyph_extents (glyph, extents);
    541 
    542     if (ret)
    543       subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
    544 
    545     return ret;
    546   }
    547 
    548   hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
    549 						hb_direction_t direction,
    550 						hb_position_t *x, hb_position_t *y)
    551   {
    552     hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
    553 
    554     if (ret)
    555       subtract_glyph_origin_for_direction (glyph, direction, x, y);
    556 
    557     return ret;
    558   }
    559 
    560   /* Generates gidDDD if glyph has no name. */
    561   void
    562   glyph_to_string (hb_codepoint_t glyph,
    563 		   char *s, unsigned int size)
    564   {
    565     if (get_glyph_name (glyph, s, size)) return;
    566 
    567     if (size && snprintf (s, size, "gid%u", glyph) < 0)
    568       *s = '\0';
    569   }
    570 
    571   /* Parses gidDDD and uniUUUU strings automatically. */
    572   hb_bool_t
    573   glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
    574 		     hb_codepoint_t *glyph)
    575   {
    576     if (get_glyph_from_name (s, len, glyph)) return true;
    577 
    578     if (len == -1) len = strlen (s);
    579 
    580     /* Straight glyph index. */
    581     if (hb_codepoint_parse (s, len, 10, glyph))
    582       return true;
    583 
    584     if (len > 3)
    585     {
    586       /* gidDDD syntax for glyph indices. */
    587       if (0 == strncmp (s, "gid", 3) &&
    588 	  hb_codepoint_parse (s + 3, len - 3, 10, glyph))
    589 	return true;
    590 
    591       /* uniUUUU and other Unicode character indices. */
    592       hb_codepoint_t unichar;
    593       if (0 == strncmp (s, "uni", 3) &&
    594 	  hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
    595 	  get_nominal_glyph (unichar, glyph))
    596 	return true;
    597     }
    598 
    599     return false;
    600   }
    601 
    602   hb_position_t em_scale (int16_t v, int scale)
    603   {
    604     int upem = face->get_upem ();
    605     int64_t scaled = v * (int64_t) scale;
    606     scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
    607     return (hb_position_t) (scaled / upem);
    608   }
    609   hb_position_t em_scalef (float v, int scale)
    610   { return (hb_position_t) round (v * scale / face->get_upem ()); }
    611   float em_fscale (int16_t v, int scale)
    612   { return (float) v * scale / face->get_upem (); }
    613 };
    614 DECLARE_NULL_INSTANCE (hb_font_t);
    615 
    616 
    617 #endif /* HB_FONT_HH */
    618