• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_IF_NOT_DEPRECATED (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    int32_t x_scale;
111    int32_t y_scale;
112    int64_t x_mult;
113    int64_t y_mult;
114  
115    unsigned int x_ppem;
116    unsigned int y_ppem;
117  
118    float ptem;
119  
120    /* Font variation coordinates. */
121    unsigned int num_coords;
122    int *coords;
123  
124    hb_font_funcs_t   *klass;
125    void              *user_data;
126    hb_destroy_func_t  destroy;
127  
128    hb_shaper_object_dataset_t<hb_font_t> data; /* Various shaper data. */
129  
130  
131    /* Convert from font-space to user-space */
dir_multhb_font_t132    int64_t dir_mult (hb_direction_t direction)
133    { return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
em_scale_xhb_font_t134    hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
em_scale_yhb_font_t135    hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
em_scalef_xhb_font_t136    hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
em_scalef_yhb_font_t137    hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
em_fscale_xhb_font_t138    float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
em_fscale_yhb_font_t139    float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
em_scale_dirhb_font_t140    hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
141    { return em_mult (v, dir_mult (direction)); }
142  
143    /* Convert from parent-font user-space to our user-space */
parent_scale_x_distancehb_font_t144    hb_position_t parent_scale_x_distance (hb_position_t v)
145    {
146      if (unlikely (parent && parent->x_scale != x_scale))
147        return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
148      return v;
149    }
parent_scale_y_distancehb_font_t150    hb_position_t parent_scale_y_distance (hb_position_t v)
151    {
152      if (unlikely (parent && parent->y_scale != y_scale))
153        return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
154      return v;
155    }
parent_scale_x_positionhb_font_t156    hb_position_t parent_scale_x_position (hb_position_t v)
157    { return parent_scale_x_distance (v); }
parent_scale_y_positionhb_font_t158    hb_position_t parent_scale_y_position (hb_position_t v)
159    { return parent_scale_y_distance (v); }
160  
parent_scale_distancehb_font_t161    void parent_scale_distance (hb_position_t *x, hb_position_t *y)
162    {
163      *x = parent_scale_x_distance (*x);
164      *y = parent_scale_y_distance (*y);
165    }
parent_scale_positionhb_font_t166    void parent_scale_position (hb_position_t *x, hb_position_t *y)
167    {
168      *x = parent_scale_x_position (*x);
169      *y = parent_scale_y_position (*y);
170    }
171  
172  
173    /* Public getters */
174  
175    HB_INTERNAL bool has_func (unsigned int i);
176    HB_INTERNAL bool has_func_set (unsigned int i);
177  
178    /* has_* ... */
179  #define HB_FONT_FUNC_IMPLEMENT(name) \
180    bool \
181    has_##name##_func () \
182    { \
183      hb_font_funcs_t *funcs = this->klass; \
184      unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
185      return has_func (i); \
186    } \
187    bool \
188    has_##name##_func_set () \
189    { \
190      hb_font_funcs_t *funcs = this->klass; \
191      unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
192      return has_func_set (i); \
193    }
194    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
195  #undef HB_FONT_FUNC_IMPLEMENT
196  
get_font_h_extentshb_font_t197    hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
198    {
199      memset (extents, 0, sizeof (*extents));
200      return klass->get.f.font_h_extents (this, user_data,
201  					extents,
202  					klass->user_data.font_h_extents);
203    }
get_font_v_extentshb_font_t204    hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
205    {
206      memset (extents, 0, sizeof (*extents));
207      return klass->get.f.font_v_extents (this, user_data,
208  					extents,
209  					klass->user_data.font_v_extents);
210    }
211  
has_glyphhb_font_t212    bool has_glyph (hb_codepoint_t unicode)
213    {
214      hb_codepoint_t glyph;
215      return get_nominal_glyph (unicode, &glyph);
216    }
217  
get_nominal_glyphhb_font_t218    hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
219  			       hb_codepoint_t *glyph)
220    {
221      *glyph = 0;
222      return klass->get.f.nominal_glyph (this, user_data,
223  				       unicode, glyph,
224  				       klass->user_data.nominal_glyph);
225    }
get_nominal_glyphshb_font_t226    unsigned int get_nominal_glyphs (unsigned int count,
227  				   const hb_codepoint_t *first_unicode,
228  				   unsigned int unicode_stride,
229  				   hb_codepoint_t *first_glyph,
230  				   unsigned int glyph_stride)
231    {
232      return klass->get.f.nominal_glyphs (this, user_data,
233  					count,
234  					first_unicode, unicode_stride,
235  					first_glyph, glyph_stride,
236  					klass->user_data.nominal_glyphs);
237    }
238  
get_variation_glyphhb_font_t239    hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
240  				 hb_codepoint_t *glyph)
241    {
242      *glyph = 0;
243      return klass->get.f.variation_glyph (this, user_data,
244  					 unicode, variation_selector, glyph,
245  					 klass->user_data.variation_glyph);
246    }
247  
get_glyph_h_advancehb_font_t248    hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
249    {
250      return klass->get.f.glyph_h_advance (this, user_data,
251  					 glyph,
252  					 klass->user_data.glyph_h_advance);
253    }
254  
get_glyph_v_advancehb_font_t255    hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
256    {
257      return klass->get.f.glyph_v_advance (this, user_data,
258  					 glyph,
259  					 klass->user_data.glyph_v_advance);
260    }
261  
get_glyph_h_advanceshb_font_t262    void get_glyph_h_advances (unsigned int count,
263  			     const hb_codepoint_t *first_glyph,
264  			     unsigned int glyph_stride,
265  			     hb_position_t *first_advance,
266  			     unsigned int advance_stride)
267    {
268      return klass->get.f.glyph_h_advances (this, user_data,
269  					  count,
270  					  first_glyph, glyph_stride,
271  					  first_advance, advance_stride,
272  					  klass->user_data.glyph_h_advances);
273    }
274  
get_glyph_v_advanceshb_font_t275    void get_glyph_v_advances (unsigned int count,
276  			     const hb_codepoint_t *first_glyph,
277  			     unsigned int glyph_stride,
278  			     hb_position_t *first_advance,
279  			     unsigned int advance_stride)
280    {
281      return klass->get.f.glyph_v_advances (this, user_data,
282  					  count,
283  					  first_glyph, glyph_stride,
284  					  first_advance, advance_stride,
285  					  klass->user_data.glyph_v_advances);
286    }
287  
get_glyph_h_originhb_font_t288    hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
289  			        hb_position_t *x, hb_position_t *y)
290    {
291      *x = *y = 0;
292      return klass->get.f.glyph_h_origin (this, user_data,
293  					glyph, x, y,
294  					klass->user_data.glyph_h_origin);
295    }
296  
get_glyph_v_originhb_font_t297    hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
298  				hb_position_t *x, hb_position_t *y)
299    {
300      *x = *y = 0;
301      return klass->get.f.glyph_v_origin (this, user_data,
302  					glyph, x, y,
303  					klass->user_data.glyph_v_origin);
304    }
305  
get_glyph_h_kerninghb_font_t306    hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
307  				     hb_codepoint_t right_glyph)
308    {
309  #ifdef HB_DISABLE_DEPRECATED
310      return 0;
311  #else
312      return klass->get.f.glyph_h_kerning (this, user_data,
313  					 left_glyph, right_glyph,
314  					 klass->user_data.glyph_h_kerning);
315  #endif
316    }
317  
get_glyph_v_kerninghb_font_t318    hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
319  				     hb_codepoint_t bottom_glyph)
320    {
321  #ifdef HB_DISABLE_DEPRECATED
322      return 0;
323  #else
324      return klass->get.f.glyph_v_kerning (this, user_data,
325  					 top_glyph, bottom_glyph,
326  					 klass->user_data.glyph_v_kerning);
327  #endif
328    }
329  
get_glyph_extentshb_font_t330    hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
331  			       hb_glyph_extents_t *extents)
332    {
333      memset (extents, 0, sizeof (*extents));
334      return klass->get.f.glyph_extents (this, user_data,
335  				       glyph,
336  				       extents,
337  				       klass->user_data.glyph_extents);
338    }
339  
get_glyph_contour_pointhb_font_t340    hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
341  					    hb_position_t *x, hb_position_t *y)
342    {
343      *x = *y = 0;
344      return klass->get.f.glyph_contour_point (this, user_data,
345  					     glyph, point_index,
346  					     x, y,
347  					     klass->user_data.glyph_contour_point);
348    }
349  
get_glyph_namehb_font_t350    hb_bool_t get_glyph_name (hb_codepoint_t glyph,
351  			    char *name, unsigned int size)
352    {
353      if (size) *name = '\0';
354      return klass->get.f.glyph_name (this, user_data,
355  				    glyph,
356  				    name, size,
357  				    klass->user_data.glyph_name);
358    }
359  
get_glyph_from_namehb_font_t360    hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
361  				 hb_codepoint_t *glyph)
362    {
363      *glyph = 0;
364      if (len == -1) len = strlen (name);
365      return klass->get.f.glyph_from_name (this, user_data,
366  					 name, len,
367  					 glyph,
368  					 klass->user_data.glyph_from_name);
369    }
370  
371  
372    /* A bit higher-level, and with fallback */
373  
get_h_extents_with_fallbackhb_font_t374    void get_h_extents_with_fallback (hb_font_extents_t *extents)
375    {
376      if (!get_font_h_extents (extents))
377      {
378        extents->ascender = y_scale * .8;
379        extents->descender = extents->ascender - y_scale;
380        extents->line_gap = 0;
381      }
382    }
get_v_extents_with_fallbackhb_font_t383    void get_v_extents_with_fallback (hb_font_extents_t *extents)
384    {
385      if (!get_font_v_extents (extents))
386      {
387        extents->ascender = x_scale / 2;
388        extents->descender = extents->ascender - x_scale;
389        extents->line_gap = 0;
390      }
391    }
392  
get_extents_for_directionhb_font_t393    void get_extents_for_direction (hb_direction_t direction,
394  				  hb_font_extents_t *extents)
395    {
396      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
397        get_h_extents_with_fallback (extents);
398      else
399        get_v_extents_with_fallback (extents);
400    }
401  
get_glyph_advance_for_directionhb_font_t402    void get_glyph_advance_for_direction (hb_codepoint_t glyph,
403  					hb_direction_t direction,
404  					hb_position_t *x, hb_position_t *y)
405    {
406      *x = *y = 0;
407      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
408        *x = get_glyph_h_advance (glyph);
409      else
410        *y = get_glyph_v_advance (glyph);
411    }
get_glyph_advances_for_directionhb_font_t412    void get_glyph_advances_for_direction (hb_direction_t direction,
413  					 unsigned int count,
414  					 const hb_codepoint_t *first_glyph,
415  					 unsigned glyph_stride,
416  					 hb_position_t *first_advance,
417  					 unsigned advance_stride)
418    {
419      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
420        get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
421      else
422        get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
423    }
424  
guess_v_origin_minus_h_originhb_font_t425    void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
426  				      hb_position_t *x, hb_position_t *y)
427    {
428      *x = get_glyph_h_advance (glyph) / 2;
429  
430      /* TODO cache this somehow?! */
431      hb_font_extents_t extents;
432      get_h_extents_with_fallback (&extents);
433      *y = extents.ascender;
434    }
435  
get_glyph_h_origin_with_fallbackhb_font_t436    void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
437  					 hb_position_t *x, hb_position_t *y)
438    {
439      if (!get_glyph_h_origin (glyph, x, y) &&
440  	 get_glyph_v_origin (glyph, x, y))
441      {
442        hb_position_t dx, dy;
443        guess_v_origin_minus_h_origin (glyph, &dx, &dy);
444        *x -= dx; *y -= dy;
445      }
446    }
get_glyph_v_origin_with_fallbackhb_font_t447    void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
448  					 hb_position_t *x, hb_position_t *y)
449    {
450      if (!get_glyph_v_origin (glyph, x, y) &&
451  	 get_glyph_h_origin (glyph, x, y))
452      {
453        hb_position_t dx, dy;
454        guess_v_origin_minus_h_origin (glyph, &dx, &dy);
455        *x += dx; *y += dy;
456      }
457    }
458  
get_glyph_origin_for_directionhb_font_t459    void get_glyph_origin_for_direction (hb_codepoint_t glyph,
460  				       hb_direction_t direction,
461  				       hb_position_t *x, hb_position_t *y)
462    {
463      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
464        get_glyph_h_origin_with_fallback (glyph, x, y);
465      else
466        get_glyph_v_origin_with_fallback (glyph, x, y);
467    }
468  
add_glyph_h_originhb_font_t469    void add_glyph_h_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_h_origin_with_fallback (glyph, &origin_x, &origin_y);
475  
476      *x += origin_x;
477      *y += origin_y;
478    }
add_glyph_v_originhb_font_t479    void add_glyph_v_origin (hb_codepoint_t glyph,
480  			   hb_position_t *x, hb_position_t *y)
481    {
482      hb_position_t origin_x, origin_y;
483  
484      get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
485  
486      *x += origin_x;
487      *y += origin_y;
488    }
add_glyph_origin_for_directionhb_font_t489    void add_glyph_origin_for_direction (hb_codepoint_t glyph,
490  				       hb_direction_t direction,
491  				       hb_position_t *x, hb_position_t *y)
492    {
493      hb_position_t origin_x, origin_y;
494  
495      get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
496  
497      *x += origin_x;
498      *y += origin_y;
499    }
500  
subtract_glyph_h_originhb_font_t501    void subtract_glyph_h_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_h_origin_with_fallback (glyph, &origin_x, &origin_y);
507  
508      *x -= origin_x;
509      *y -= origin_y;
510    }
subtract_glyph_v_originhb_font_t511    void subtract_glyph_v_origin (hb_codepoint_t glyph,
512  				hb_position_t *x, hb_position_t *y)
513    {
514      hb_position_t origin_x, origin_y;
515  
516      get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
517  
518      *x -= origin_x;
519      *y -= origin_y;
520    }
subtract_glyph_origin_for_directionhb_font_t521    void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
522  					    hb_direction_t direction,
523  					    hb_position_t *x, hb_position_t *y)
524    {
525      hb_position_t origin_x, origin_y;
526  
527      get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
528  
529      *x -= origin_x;
530      *y -= origin_y;
531    }
532  
get_glyph_kerning_for_directionhb_font_t533    void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
534  					hb_direction_t direction,
535  					hb_position_t *x, hb_position_t *y)
536    {
537      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
538        *y = 0;
539        *x = get_glyph_h_kerning (first_glyph, second_glyph);
540      } else {
541        *x = 0;
542        *y = get_glyph_v_kerning (first_glyph, second_glyph);
543      }
544    }
545  
get_glyph_extents_for_originhb_font_t546    hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
547  					  hb_direction_t direction,
548  					  hb_glyph_extents_t *extents)
549    {
550      hb_bool_t ret = get_glyph_extents (glyph, extents);
551  
552      if (ret)
553        subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
554  
555      return ret;
556    }
557  
get_glyph_contour_point_for_originhb_font_t558    hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
559  						hb_direction_t direction,
560  						hb_position_t *x, hb_position_t *y)
561    {
562      hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
563  
564      if (ret)
565        subtract_glyph_origin_for_direction (glyph, direction, x, y);
566  
567      return ret;
568    }
569  
570    /* Generates gidDDD if glyph has no name. */
571    void
glyph_to_stringhb_font_t572    glyph_to_string (hb_codepoint_t glyph,
573  		   char *s, unsigned int size)
574    {
575      if (get_glyph_name (glyph, s, size)) return;
576  
577      if (size && snprintf (s, size, "gid%u", glyph) < 0)
578        *s = '\0';
579    }
580  
581    /* Parses gidDDD and uniUUUU strings automatically. */
582    hb_bool_t
glyph_from_stringhb_font_t583    glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
584  		     hb_codepoint_t *glyph)
585    {
586      if (get_glyph_from_name (s, len, glyph)) return true;
587  
588      if (len == -1) len = strlen (s);
589  
590      /* Straight glyph index. */
591      if (hb_codepoint_parse (s, len, 10, glyph))
592        return true;
593  
594      if (len > 3)
595      {
596        /* gidDDD syntax for glyph indices. */
597        if (0 == strncmp (s, "gid", 3) &&
598  	  hb_codepoint_parse (s + 3, len - 3, 10, glyph))
599  	return true;
600  
601        /* uniUUUU and other Unicode character indices. */
602        hb_codepoint_t unichar;
603        if (0 == strncmp (s, "uni", 3) &&
604  	  hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
605  	  get_nominal_glyph (unichar, glyph))
606  	return true;
607      }
608  
609      return false;
610    }
611  
mults_changedhb_font_t612    void mults_changed ()
613    {
614      signed upem = face->get_upem ();
615      x_mult = ((int64_t) x_scale << 16) / upem;
616      y_mult = ((int64_t) y_scale << 16) / upem;
617    }
618  
em_multhb_font_t619    hb_position_t em_mult (int16_t v, int64_t mult)
620    {
621      return (hb_position_t) ((v * mult) >> 16);
622    }
em_scalefhb_font_t623    hb_position_t em_scalef (float v, int scale)
624    { return (hb_position_t) roundf (v * scale / face->get_upem ()); }
em_fscalehb_font_t625    float em_fscale (int16_t v, int scale)
626    { return (float) v * scale / face->get_upem (); }
627  };
628  DECLARE_NULL_INSTANCE (hb_font_t);
629  
630  
631  #endif /* HB_FONT_HH */
632