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