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.hh"
28
29 #ifndef HB_NO_OT_FONT
30
31 #include "hb-ot.h"
32
33 #include "hb-cache.hh"
34 #include "hb-font.hh"
35 #include "hb-machinery.hh"
36 #include "hb-ot-face.hh"
37
38 #include "hb-ot-cmap-table.hh"
39 #include "hb-ot-glyf-table.hh"
40 #include "hb-ot-cff1-table.hh"
41 #include "hb-ot-cff2-table.hh"
42 #include "hb-ot-hmtx-table.hh"
43 #include "hb-ot-post-table.hh"
44 #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
45 #include "hb-ot-vorg-table.hh"
46 #include "hb-ot-color-cbdt-table.hh"
47 #include "hb-ot-color-sbix-table.hh"
48 #include "hb-ot-color-colr-table.hh"
49
50
51 /**
52 * SECTION:hb-ot-font
53 * @title: hb-ot-font
54 * @short_description: OpenType font implementation
55 * @include: hb-ot.h
56 *
57 * Functions for using OpenType fonts with hb_shape(). Note that fonts returned
58 * by hb_font_create() default to using these functions, so most clients would
59 * never need to call these functions directly.
60 **/
61
62 using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
63
64 struct hb_ot_font_t
65 {
66 const hb_ot_face_t *ot_face;
67
68 /* h_advance caching */
69 mutable hb_atomic_int_t cached_coords_serial;
70 mutable hb_atomic_ptr_t<hb_ot_font_advance_cache_t> advance_cache;
71 };
72
73 static hb_ot_font_t *
_hb_ot_font_create(hb_font_t * font)74 _hb_ot_font_create (hb_font_t *font)
75 {
76 hb_ot_font_t *ot_font = (hb_ot_font_t *) hb_calloc (1, sizeof (hb_ot_font_t));
77 if (unlikely (!ot_font))
78 return nullptr;
79
80 ot_font->ot_face = &font->face->table;
81
82 return ot_font;
83 }
84
85 static void
_hb_ot_font_destroy(void * font_data)86 _hb_ot_font_destroy (void *font_data)
87 {
88 hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data;
89
90 auto *cache = ot_font->advance_cache.get_relaxed ();
91 if (cache)
92 {
93 cache->fini ();
94 hb_free (cache);
95 }
96
97 hb_free (ot_font);
98 }
99
100 static hb_bool_t
hb_ot_get_nominal_glyph(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t unicode,hb_codepoint_t * glyph,void * user_data HB_UNUSED)101 hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
102 void *font_data,
103 hb_codepoint_t unicode,
104 hb_codepoint_t *glyph,
105 void *user_data HB_UNUSED)
106 {
107 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
108 const hb_ot_face_t *ot_face = ot_font->ot_face;
109 return ot_face->cmap->get_nominal_glyph (unicode, glyph);
110 }
111
112 static unsigned int
hb_ot_get_nominal_glyphs(hb_font_t * font HB_UNUSED,void * font_data,unsigned int count,const hb_codepoint_t * first_unicode,unsigned int unicode_stride,hb_codepoint_t * first_glyph,unsigned int glyph_stride,void * user_data HB_UNUSED)113 hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
114 void *font_data,
115 unsigned int count,
116 const hb_codepoint_t *first_unicode,
117 unsigned int unicode_stride,
118 hb_codepoint_t *first_glyph,
119 unsigned int glyph_stride,
120 void *user_data HB_UNUSED)
121 {
122 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
123 const hb_ot_face_t *ot_face = ot_font->ot_face;
124 return ot_face->cmap->get_nominal_glyphs (count,
125 first_unicode, unicode_stride,
126 first_glyph, glyph_stride);
127 }
128
129 static hb_bool_t
hb_ot_get_variation_glyph(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t unicode,hb_codepoint_t variation_selector,hb_codepoint_t * glyph,void * user_data HB_UNUSED)130 hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
131 void *font_data,
132 hb_codepoint_t unicode,
133 hb_codepoint_t variation_selector,
134 hb_codepoint_t *glyph,
135 void *user_data HB_UNUSED)
136 {
137 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
138 const hb_ot_face_t *ot_face = ot_font->ot_face;
139 return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph);
140 }
141
142 static void
hb_ot_get_glyph_h_advances(hb_font_t * font,void * font_data,unsigned count,const hb_codepoint_t * first_glyph,unsigned glyph_stride,hb_position_t * first_advance,unsigned advance_stride,void * user_data HB_UNUSED)143 hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
144 unsigned count,
145 const hb_codepoint_t *first_glyph,
146 unsigned glyph_stride,
147 hb_position_t *first_advance,
148 unsigned advance_stride,
149 void *user_data HB_UNUSED)
150 {
151 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
152 const hb_ot_face_t *ot_face = ot_font->ot_face;
153 const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
154
155 #ifndef HB_NO_VAR
156 const OT::HVAR &HVAR = *hmtx.var_table;
157 const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
158 OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
159
160 bool use_cache = font->num_coords;
161 #else
162 OT::VariationStore::cache_t *varStore_cache = nullptr;
163 bool use_cache = false;
164 #endif
165
166 hb_ot_font_advance_cache_t *cache = nullptr;
167 if (use_cache)
168 {
169 retry:
170 cache = ot_font->advance_cache.get_acquire ();
171 if (unlikely (!cache))
172 {
173 cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t));
174 if (unlikely (!cache))
175 {
176 use_cache = false;
177 goto out;
178 }
179
180 cache->init ();
181 if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache)))
182 {
183 hb_free (cache);
184 goto retry;
185 }
186 ot_font->cached_coords_serial.set_release (font->serial_coords);
187 }
188 }
189 out:
190
191 if (!use_cache)
192 {
193 for (unsigned int i = 0; i < count; i++)
194 {
195 *first_advance = font->em_scale_x (hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
196 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
197 first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
198 }
199 }
200 else
201 { /* Use cache. */
202 if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords)
203 {
204 ot_font->advance_cache->init ();
205 ot_font->cached_coords_serial.set_release (font->serial_coords);
206 }
207
208 for (unsigned int i = 0; i < count; i++)
209 {
210 hb_position_t v;
211 unsigned cv;
212 if (ot_font->advance_cache->get (*first_glyph, &cv))
213 v = cv;
214 else
215 {
216 v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
217 ot_font->advance_cache->set (*first_glyph, v);
218 }
219 *first_advance = font->em_scale_x (v);
220 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
221 first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
222 }
223 }
224
225 #ifndef HB_NO_VAR
226 OT::VariationStore::destroy_cache (varStore_cache);
227 #endif
228 }
229
230 #ifndef HB_NO_VERTICAL
231 static void
hb_ot_get_glyph_v_advances(hb_font_t * font,void * font_data,unsigned count,const hb_codepoint_t * first_glyph,unsigned glyph_stride,hb_position_t * first_advance,unsigned advance_stride,void * user_data HB_UNUSED)232 hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
233 unsigned count,
234 const hb_codepoint_t *first_glyph,
235 unsigned glyph_stride,
236 hb_position_t *first_advance,
237 unsigned advance_stride,
238 void *user_data HB_UNUSED)
239 {
240 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
241 const hb_ot_face_t *ot_face = ot_font->ot_face;
242 const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
243
244 if (vmtx.has_data ())
245 {
246 #ifndef HB_NO_VAR
247 const OT::VVAR &VVAR = *vmtx.var_table;
248 const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
249 OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
250 #else
251 OT::VariationStore::cache_t *varStore_cache = nullptr;
252 #endif
253
254 for (unsigned int i = 0; i < count; i++)
255 {
256 *first_advance = font->em_scale_y (-(int) vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
257 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
258 first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
259 }
260
261 #ifndef HB_NO_VAR
262 OT::VariationStore::destroy_cache (varStore_cache);
263 #endif
264 }
265 else
266 {
267 hb_font_extents_t font_extents;
268 font->get_h_extents_with_fallback (&font_extents);
269 hb_position_t advance = -(font_extents.ascender - font_extents.descender);
270
271 for (unsigned int i = 0; i < count; i++)
272 {
273 *first_advance = advance;
274 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
275 first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
276 }
277 }
278 }
279 #endif
280
281 #ifndef HB_NO_VERTICAL
282 static hb_bool_t
hb_ot_get_glyph_v_origin(hb_font_t * font,void * font_data,hb_codepoint_t glyph,hb_position_t * x,hb_position_t * y,void * user_data HB_UNUSED)283 hb_ot_get_glyph_v_origin (hb_font_t *font,
284 void *font_data,
285 hb_codepoint_t glyph,
286 hb_position_t *x,
287 hb_position_t *y,
288 void *user_data HB_UNUSED)
289 {
290 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
291 const hb_ot_face_t *ot_face = ot_font->ot_face;
292
293 *x = font->get_glyph_h_advance (glyph) / 2;
294
295 const OT::VORG &VORG = *ot_face->VORG;
296 if (VORG.has_data ())
297 {
298 float delta = 0;
299
300 #ifndef HB_NO_VAR
301 const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
302 const OT::VVAR &VVAR = *vmtx.var_table;
303 if (font->num_coords)
304 VVAR.get_vorg_delta_unscaled (glyph,
305 font->coords, font->num_coords,
306 &delta);
307 #endif
308
309 *y = font->em_scalef_y (VORG.get_y_origin (glyph) + delta);
310 return true;
311 }
312
313 hb_glyph_extents_t extents = {0};
314 if (ot_face->glyf->get_extents (font, glyph, &extents))
315 {
316 const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
317 int tsb = 0;
318 if (vmtx.get_leading_bearing_with_var_unscaled (font, glyph, &tsb))
319 {
320 *y = extents.y_bearing + font->em_scale_y (tsb);
321 return true;
322 }
323
324 hb_font_extents_t font_extents;
325 font->get_h_extents_with_fallback (&font_extents);
326 hb_position_t advance = font_extents.ascender - font_extents.descender;
327 int diff = advance - -extents.height;
328 *y = extents.y_bearing + (diff >> 1);
329 return true;
330 }
331
332 hb_font_extents_t font_extents;
333 font->get_h_extents_with_fallback (&font_extents);
334 *y = font_extents.ascender;
335
336 return true;
337 }
338 #endif
339
340 static hb_bool_t
hb_ot_get_glyph_extents(hb_font_t * font,void * font_data,hb_codepoint_t glyph,hb_glyph_extents_t * extents,void * user_data HB_UNUSED)341 hb_ot_get_glyph_extents (hb_font_t *font,
342 void *font_data,
343 hb_codepoint_t glyph,
344 hb_glyph_extents_t *extents,
345 void *user_data HB_UNUSED)
346 {
347 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
348 const hb_ot_face_t *ot_face = ot_font->ot_face;
349
350 #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
351 if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
352 if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
353 #endif
354 #if !defined(HB_NO_COLOR)
355 if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
356 #endif
357 if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
358 #ifndef HB_NO_OT_FONT_CFF
359 if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
360 if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
361 #endif
362
363 return false;
364 }
365
366 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
367 static hb_bool_t
hb_ot_get_glyph_name(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t glyph,char * name,unsigned int size,void * user_data HB_UNUSED)368 hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
369 void *font_data,
370 hb_codepoint_t glyph,
371 char *name, unsigned int size,
372 void *user_data HB_UNUSED)
373 {
374 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
375 const hb_ot_face_t *ot_face = ot_font->ot_face;
376
377 if (ot_face->post->get_glyph_name (glyph, name, size)) return true;
378 #ifndef HB_NO_OT_FONT_CFF
379 if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true;
380 #endif
381 return false;
382 }
383 static hb_bool_t
hb_ot_get_glyph_from_name(hb_font_t * font HB_UNUSED,void * font_data,const char * name,int len,hb_codepoint_t * glyph,void * user_data HB_UNUSED)384 hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
385 void *font_data,
386 const char *name, int len,
387 hb_codepoint_t *glyph,
388 void *user_data HB_UNUSED)
389 {
390 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
391 const hb_ot_face_t *ot_face = ot_font->ot_face;
392
393 if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true;
394 #ifndef HB_NO_OT_FONT_CFF
395 if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true;
396 #endif
397 return false;
398 }
399 #endif
400
401 static hb_bool_t
hb_ot_get_font_h_extents(hb_font_t * font,void * font_data HB_UNUSED,hb_font_extents_t * metrics,void * user_data HB_UNUSED)402 hb_ot_get_font_h_extents (hb_font_t *font,
403 void *font_data HB_UNUSED,
404 hb_font_extents_t *metrics,
405 void *user_data HB_UNUSED)
406 {
407 return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
408 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
409 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
410 }
411
412 #ifndef HB_NO_VERTICAL
413 static hb_bool_t
hb_ot_get_font_v_extents(hb_font_t * font,void * font_data HB_UNUSED,hb_font_extents_t * metrics,void * user_data HB_UNUSED)414 hb_ot_get_font_v_extents (hb_font_t *font,
415 void *font_data HB_UNUSED,
416 hb_font_extents_t *metrics,
417 void *user_data HB_UNUSED)
418 {
419 return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_ASCENDER, &metrics->ascender) &&
420 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) &&
421 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
422 }
423 #endif
424
425 #ifndef HB_NO_DRAW
426 static void
hb_ot_get_glyph_shape(hb_font_t * font,void * font_data HB_UNUSED,hb_codepoint_t glyph,hb_draw_funcs_t * draw_funcs,void * draw_data,void * user_data)427 hb_ot_get_glyph_shape (hb_font_t *font,
428 void *font_data HB_UNUSED,
429 hb_codepoint_t glyph,
430 hb_draw_funcs_t *draw_funcs, void *draw_data,
431 void *user_data)
432 {
433 hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
434 if (font->face->table.glyf->get_path (font, glyph, draw_session)) return;
435 #ifndef HB_NO_CFF
436 if (font->face->table.cff1->get_path (font, glyph, draw_session)) return;
437 if (font->face->table.cff2->get_path (font, glyph, draw_session)) return;
438 #endif
439 }
440 #endif
441
442 static inline void free_static_ot_funcs ();
443
444 static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
445 {
createhb_ot_font_funcs_lazy_loader_t446 static hb_font_funcs_t *create ()
447 {
448 hb_font_funcs_t *funcs = hb_font_funcs_create ();
449
450 hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
451 hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr);
452 hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
453
454 hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
455 hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr);
456 //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
457
458 #ifndef HB_NO_VERTICAL
459 hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
460 hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr);
461 hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
462 #endif
463
464 #ifndef HB_NO_DRAW
465 hb_font_funcs_set_glyph_shape_func (funcs, hb_ot_get_glyph_shape, nullptr, nullptr);
466 #endif
467
468 hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
469 //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
470
471 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
472 hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
473 hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
474 #endif
475
476 hb_font_funcs_make_immutable (funcs);
477
478 hb_atexit (free_static_ot_funcs);
479
480 return funcs;
481 }
482 } static_ot_funcs;
483
484 static inline
free_static_ot_funcs()485 void free_static_ot_funcs ()
486 {
487 static_ot_funcs.free_instance ();
488 }
489
490 static hb_font_funcs_t *
_hb_ot_get_font_funcs()491 _hb_ot_get_font_funcs ()
492 {
493 return static_ot_funcs.get_unconst ();
494 }
495
496
497 /**
498 * hb_ot_font_set_funcs:
499 * @font: #hb_font_t to work upon
500 *
501 * Sets the font functions to use when working with @font.
502 *
503 * Since: 0.9.28
504 **/
505 void
hb_ot_font_set_funcs(hb_font_t * font)506 hb_ot_font_set_funcs (hb_font_t *font)
507 {
508 hb_ot_font_t *ot_font = _hb_ot_font_create (font);
509 if (unlikely (!ot_font))
510 return;
511
512 hb_font_set_funcs (font,
513 _hb_ot_get_font_funcs (),
514 ot_font,
515 _hb_ot_font_destroy);
516 }
517
518 #ifndef HB_NO_VAR
519 bool
_glyf_get_leading_bearing_with_var_unscaled(hb_font_t * font,hb_codepoint_t glyph,bool is_vertical,int * lsb)520 _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
521 int *lsb)
522 {
523 return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
524 }
525
526 unsigned
_glyf_get_advance_with_var_unscaled(hb_font_t * font,hb_codepoint_t glyph,bool is_vertical)527 _glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
528 {
529 return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
530 }
531 #endif
532
533
534 #endif
535