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   float slant;
113   float slant_xy;
114   int64_t x_mult;
115   int64_t y_mult;
116 
117   unsigned int x_ppem;
118   unsigned int y_ppem;
119 
120   float ptem;
121 
122   /* Font variation coordinates. */
123   unsigned int num_coords;
124   int *coords;
125   float *design_coords;
126 
127   hb_font_funcs_t   *klass;
128   void              *user_data;
129   hb_destroy_func_t  destroy;
130 
131   hb_shaper_object_dataset_t<hb_font_t> data; /* Various shaper data. */
132 
133 
134   /* Convert from font-space to user-space */
dir_multhb_font_t135   int64_t dir_mult (hb_direction_t direction)
136   { return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
em_scale_xhb_font_t137   hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
em_scale_yhb_font_t138   hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
em_scalef_xhb_font_t139   hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
em_scalef_yhb_font_t140   hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
em_fscale_xhb_font_t141   float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
em_fscale_yhb_font_t142   float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
em_scale_dirhb_font_t143   hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
144   { return em_mult (v, dir_mult (direction)); }
145 
146   /* Convert from parent-font user-space to our user-space */
parent_scale_x_distancehb_font_t147   hb_position_t parent_scale_x_distance (hb_position_t v)
148   {
149     if (unlikely (parent && parent->x_scale != x_scale))
150       return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
151     return v;
152   }
parent_scale_y_distancehb_font_t153   hb_position_t parent_scale_y_distance (hb_position_t v)
154   {
155     if (unlikely (parent && parent->y_scale != y_scale))
156       return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
157     return v;
158   }
parent_scale_x_positionhb_font_t159   hb_position_t parent_scale_x_position (hb_position_t v)
160   { return parent_scale_x_distance (v); }
parent_scale_y_positionhb_font_t161   hb_position_t parent_scale_y_position (hb_position_t v)
162   { return parent_scale_y_distance (v); }
163 
parent_scale_distancehb_font_t164   void parent_scale_distance (hb_position_t *x, hb_position_t *y)
165   {
166     *x = parent_scale_x_distance (*x);
167     *y = parent_scale_y_distance (*y);
168   }
parent_scale_positionhb_font_t169   void parent_scale_position (hb_position_t *x, hb_position_t *y)
170   {
171     *x = parent_scale_x_position (*x);
172     *y = parent_scale_y_position (*y);
173   }
174 
175 
176   /* Public getters */
177 
178   HB_INTERNAL bool has_func (unsigned int i);
179   HB_INTERNAL bool has_func_set (unsigned int i);
180 
181   /* has_* ... */
182 #define HB_FONT_FUNC_IMPLEMENT(name) \
183   bool \
184   has_##name##_func () \
185   { \
186     hb_font_funcs_t *funcs = this->klass; \
187     unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
188     return has_func (i); \
189   } \
190   bool \
191   has_##name##_func_set () \
192   { \
193     hb_font_funcs_t *funcs = this->klass; \
194     unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
195     return has_func_set (i); \
196   }
197   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
198 #undef HB_FONT_FUNC_IMPLEMENT
199 
get_font_h_extentshb_font_t200   hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
201   {
202     memset (extents, 0, sizeof (*extents));
203     return klass->get.f.font_h_extents (this, user_data,
204 					extents,
205 					klass->user_data.font_h_extents);
206   }
get_font_v_extentshb_font_t207   hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
208   {
209     memset (extents, 0, sizeof (*extents));
210     return klass->get.f.font_v_extents (this, user_data,
211 					extents,
212 					klass->user_data.font_v_extents);
213   }
214 
has_glyphhb_font_t215   bool has_glyph (hb_codepoint_t unicode)
216   {
217     hb_codepoint_t glyph;
218     return get_nominal_glyph (unicode, &glyph);
219   }
220 
get_nominal_glyphhb_font_t221   hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
222 			       hb_codepoint_t *glyph,
223 			       hb_codepoint_t not_found = 0)
224   {
225     *glyph = not_found;
226     return klass->get.f.nominal_glyph (this, user_data,
227 				       unicode, glyph,
228 				       klass->user_data.nominal_glyph);
229   }
get_nominal_glyphshb_font_t230   unsigned int get_nominal_glyphs (unsigned int count,
231 				   const hb_codepoint_t *first_unicode,
232 				   unsigned int unicode_stride,
233 				   hb_codepoint_t *first_glyph,
234 				   unsigned int glyph_stride)
235   {
236     return klass->get.f.nominal_glyphs (this, user_data,
237 					count,
238 					first_unicode, unicode_stride,
239 					first_glyph, glyph_stride,
240 					klass->user_data.nominal_glyphs);
241   }
242 
get_variation_glyphhb_font_t243   hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
244 				 hb_codepoint_t *glyph,
245 				 hb_codepoint_t not_found = 0)
246   {
247     *glyph = not_found;
248     return klass->get.f.variation_glyph (this, user_data,
249 					 unicode, variation_selector, glyph,
250 					 klass->user_data.variation_glyph);
251   }
252 
get_glyph_h_advancehb_font_t253   hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
254   {
255     return klass->get.f.glyph_h_advance (this, user_data,
256 					 glyph,
257 					 klass->user_data.glyph_h_advance);
258   }
259 
get_glyph_v_advancehb_font_t260   hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
261   {
262     return klass->get.f.glyph_v_advance (this, user_data,
263 					 glyph,
264 					 klass->user_data.glyph_v_advance);
265   }
266 
get_glyph_h_advanceshb_font_t267   void get_glyph_h_advances (unsigned int count,
268 			     const hb_codepoint_t *first_glyph,
269 			     unsigned int glyph_stride,
270 			     hb_position_t *first_advance,
271 			     unsigned int advance_stride)
272   {
273     return klass->get.f.glyph_h_advances (this, user_data,
274 					  count,
275 					  first_glyph, glyph_stride,
276 					  first_advance, advance_stride,
277 					  klass->user_data.glyph_h_advances);
278   }
279 
get_glyph_v_advanceshb_font_t280   void get_glyph_v_advances (unsigned int count,
281 			     const hb_codepoint_t *first_glyph,
282 			     unsigned int glyph_stride,
283 			     hb_position_t *first_advance,
284 			     unsigned int advance_stride)
285   {
286     return klass->get.f.glyph_v_advances (this, user_data,
287 					  count,
288 					  first_glyph, glyph_stride,
289 					  first_advance, advance_stride,
290 					  klass->user_data.glyph_v_advances);
291   }
292 
get_glyph_h_originhb_font_t293   hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
294 				hb_position_t *x, hb_position_t *y)
295   {
296     *x = *y = 0;
297     return klass->get.f.glyph_h_origin (this, user_data,
298 					glyph, x, y,
299 					klass->user_data.glyph_h_origin);
300   }
301 
get_glyph_v_originhb_font_t302   hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
303 				hb_position_t *x, hb_position_t *y)
304   {
305     *x = *y = 0;
306     return klass->get.f.glyph_v_origin (this, user_data,
307 					glyph, x, y,
308 					klass->user_data.glyph_v_origin);
309   }
310 
get_glyph_h_kerninghb_font_t311   hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
312 				     hb_codepoint_t right_glyph)
313   {
314 #ifdef HB_DISABLE_DEPRECATED
315     return 0;
316 #else
317     return klass->get.f.glyph_h_kerning (this, user_data,
318 					 left_glyph, right_glyph,
319 					 klass->user_data.glyph_h_kerning);
320 #endif
321   }
322 
get_glyph_v_kerninghb_font_t323   hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
324 				     hb_codepoint_t bottom_glyph)
325   {
326 #ifdef HB_DISABLE_DEPRECATED
327     return 0;
328 #else
329     return klass->get.f.glyph_v_kerning (this, user_data,
330 					 top_glyph, bottom_glyph,
331 					 klass->user_data.glyph_v_kerning);
332 #endif
333   }
334 
get_glyph_extentshb_font_t335   hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
336 			       hb_glyph_extents_t *extents)
337   {
338     memset (extents, 0, sizeof (*extents));
339     return klass->get.f.glyph_extents (this, user_data,
340 				       glyph,
341 				       extents,
342 				       klass->user_data.glyph_extents);
343   }
344 
get_glyph_contour_pointhb_font_t345   hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
346 				     hb_position_t *x, hb_position_t *y)
347   {
348     *x = *y = 0;
349     return klass->get.f.glyph_contour_point (this, user_data,
350 					     glyph, point_index,
351 					     x, y,
352 					     klass->user_data.glyph_contour_point);
353   }
354 
get_glyph_namehb_font_t355   hb_bool_t get_glyph_name (hb_codepoint_t glyph,
356 			    char *name, unsigned int size)
357   {
358     if (size) *name = '\0';
359     return klass->get.f.glyph_name (this, user_data,
360 				    glyph,
361 				    name, size,
362 				    klass->user_data.glyph_name);
363   }
364 
get_glyph_from_namehb_font_t365   hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
366 				 hb_codepoint_t *glyph)
367   {
368     *glyph = 0;
369     if (len == -1) len = strlen (name);
370     return klass->get.f.glyph_from_name (this, user_data,
371 					 name, len,
372 					 glyph,
373 					 klass->user_data.glyph_from_name);
374   }
375 
376 
377   /* A bit higher-level, and with fallback */
378 
get_h_extents_with_fallbackhb_font_t379   void get_h_extents_with_fallback (hb_font_extents_t *extents)
380   {
381     if (!get_font_h_extents (extents))
382     {
383       extents->ascender = y_scale * .8;
384       extents->descender = extents->ascender - y_scale;
385       extents->line_gap = 0;
386     }
387   }
get_v_extents_with_fallbackhb_font_t388   void get_v_extents_with_fallback (hb_font_extents_t *extents)
389   {
390     if (!get_font_v_extents (extents))
391     {
392       extents->ascender = x_scale / 2;
393       extents->descender = extents->ascender - x_scale;
394       extents->line_gap = 0;
395     }
396   }
397 
get_extents_for_directionhb_font_t398   void get_extents_for_direction (hb_direction_t direction,
399 				  hb_font_extents_t *extents)
400   {
401     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
402       get_h_extents_with_fallback (extents);
403     else
404       get_v_extents_with_fallback (extents);
405   }
406 
get_glyph_advance_for_directionhb_font_t407   void get_glyph_advance_for_direction (hb_codepoint_t glyph,
408 					hb_direction_t direction,
409 					hb_position_t *x, hb_position_t *y)
410   {
411     *x = *y = 0;
412     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
413       *x = get_glyph_h_advance (glyph);
414     else
415       *y = get_glyph_v_advance (glyph);
416   }
get_glyph_advances_for_directionhb_font_t417   void get_glyph_advances_for_direction (hb_direction_t direction,
418 					 unsigned int count,
419 					 const hb_codepoint_t *first_glyph,
420 					 unsigned glyph_stride,
421 					 hb_position_t *first_advance,
422 					 unsigned advance_stride)
423   {
424     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
425       get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
426     else
427       get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
428   }
429 
guess_v_origin_minus_h_originhb_font_t430   void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
431 				      hb_position_t *x, hb_position_t *y)
432   {
433     *x = get_glyph_h_advance (glyph) / 2;
434 
435     /* TODO cache this somehow?! */
436     hb_font_extents_t extents;
437     get_h_extents_with_fallback (&extents);
438     *y = extents.ascender;
439   }
440 
get_glyph_h_origin_with_fallbackhb_font_t441   void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
442 					 hb_position_t *x, hb_position_t *y)
443   {
444     if (!get_glyph_h_origin (glyph, x, y) &&
445 	 get_glyph_v_origin (glyph, x, y))
446     {
447       hb_position_t dx, dy;
448       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
449       *x -= dx; *y -= dy;
450     }
451   }
get_glyph_v_origin_with_fallbackhb_font_t452   void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
453 					 hb_position_t *x, hb_position_t *y)
454   {
455     if (!get_glyph_v_origin (glyph, x, y) &&
456 	 get_glyph_h_origin (glyph, x, y))
457     {
458       hb_position_t dx, dy;
459       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
460       *x += dx; *y += dy;
461     }
462   }
463 
get_glyph_origin_for_directionhb_font_t464   void get_glyph_origin_for_direction (hb_codepoint_t glyph,
465 				       hb_direction_t direction,
466 				       hb_position_t *x, hb_position_t *y)
467   {
468     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
469       get_glyph_h_origin_with_fallback (glyph, x, y);
470     else
471       get_glyph_v_origin_with_fallback (glyph, x, y);
472   }
473 
add_glyph_h_originhb_font_t474   void add_glyph_h_origin (hb_codepoint_t glyph,
475 			   hb_position_t *x, hb_position_t *y)
476   {
477     hb_position_t origin_x, origin_y;
478 
479     get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
480 
481     *x += origin_x;
482     *y += origin_y;
483   }
add_glyph_v_originhb_font_t484   void add_glyph_v_origin (hb_codepoint_t glyph,
485 			   hb_position_t *x, hb_position_t *y)
486   {
487     hb_position_t origin_x, origin_y;
488 
489     get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
490 
491     *x += origin_x;
492     *y += origin_y;
493   }
add_glyph_origin_for_directionhb_font_t494   void add_glyph_origin_for_direction (hb_codepoint_t glyph,
495 				       hb_direction_t direction,
496 				       hb_position_t *x, hb_position_t *y)
497   {
498     hb_position_t origin_x, origin_y;
499 
500     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
501 
502     *x += origin_x;
503     *y += origin_y;
504   }
505 
subtract_glyph_h_originhb_font_t506   void subtract_glyph_h_origin (hb_codepoint_t glyph,
507 				hb_position_t *x, hb_position_t *y)
508   {
509     hb_position_t origin_x, origin_y;
510 
511     get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
512 
513     *x -= origin_x;
514     *y -= origin_y;
515   }
subtract_glyph_v_originhb_font_t516   void subtract_glyph_v_origin (hb_codepoint_t glyph,
517 				hb_position_t *x, hb_position_t *y)
518   {
519     hb_position_t origin_x, origin_y;
520 
521     get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
522 
523     *x -= origin_x;
524     *y -= origin_y;
525   }
subtract_glyph_origin_for_directionhb_font_t526   void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
527 					    hb_direction_t direction,
528 					    hb_position_t *x, hb_position_t *y)
529   {
530     hb_position_t origin_x, origin_y;
531 
532     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
533 
534     *x -= origin_x;
535     *y -= origin_y;
536   }
537 
get_glyph_kerning_for_directionhb_font_t538   void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
539 					hb_direction_t direction,
540 					hb_position_t *x, hb_position_t *y)
541   {
542     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
543       *y = 0;
544       *x = get_glyph_h_kerning (first_glyph, second_glyph);
545     } else {
546       *x = 0;
547       *y = get_glyph_v_kerning (first_glyph, second_glyph);
548     }
549   }
550 
get_glyph_extents_for_originhb_font_t551   hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
552 					  hb_direction_t direction,
553 					  hb_glyph_extents_t *extents)
554   {
555     hb_bool_t ret = get_glyph_extents (glyph, extents);
556 
557     if (ret)
558       subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
559 
560     return ret;
561   }
562 
get_glyph_contour_point_for_originhb_font_t563   hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
564 						hb_direction_t direction,
565 						hb_position_t *x, hb_position_t *y)
566   {
567     hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
568 
569     if (ret)
570       subtract_glyph_origin_for_direction (glyph, direction, x, y);
571 
572     return ret;
573   }
574 
575   /* Generates gidDDD if glyph has no name. */
576   void
glyph_to_stringhb_font_t577   glyph_to_string (hb_codepoint_t glyph,
578 		   char *s, unsigned int size)
579   {
580     if (get_glyph_name (glyph, s, size)) return;
581 
582     if (size && snprintf (s, size, "gid%u", glyph) < 0)
583       *s = '\0';
584   }
585 
586   /* Parses gidDDD and uniUUUU strings automatically. */
587   hb_bool_t
glyph_from_stringhb_font_t588   glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
589 		     hb_codepoint_t *glyph)
590   {
591     if (get_glyph_from_name (s, len, glyph)) return true;
592 
593     if (len == -1) len = strlen (s);
594 
595     /* Straight glyph index. */
596     if (hb_codepoint_parse (s, len, 10, glyph))
597       return true;
598 
599     if (len > 3)
600     {
601       /* gidDDD syntax for glyph indices. */
602       if (0 == strncmp (s, "gid", 3) &&
603 	  hb_codepoint_parse (s + 3, len - 3, 10, glyph))
604 	return true;
605 
606       /* uniUUUU and other Unicode character indices. */
607       hb_codepoint_t unichar;
608       if (0 == strncmp (s, "uni", 3) &&
609 	  hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
610 	  get_nominal_glyph (unichar, glyph))
611 	return true;
612     }
613 
614     return false;
615   }
616 
mults_changedhb_font_t617   void mults_changed ()
618   {
619     signed upem = face->get_upem ();
620     x_mult = ((int64_t) x_scale << 16) / upem;
621     y_mult = ((int64_t) y_scale << 16) / upem;
622     slant_xy = y_scale ? slant * x_scale / y_scale : 0.f;
623   }
624 
em_multhb_font_t625   hb_position_t em_mult (int16_t v, int64_t mult)
626   { return (hb_position_t) ((v * mult + 32768) >> 16); }
em_scalefhb_font_t627   hb_position_t em_scalef (float v, int scale)
628   { return (hb_position_t) roundf (v * scale / face->get_upem ()); }
em_fscalehb_font_t629   float em_fscale (int16_t v, int scale)
630   { return (float) v * scale / face->get_upem (); }
631 };
632 DECLARE_NULL_INSTANCE (hb_font_t);
633 
634 
635 #endif /* HB_FONT_HH */
636