2 * Copyright © 2011,2014 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
33 #include "hb-cache.hh"
35 #include "hb-machinery.hh"
36 #include "hb-ot-face.hh"
37 #include "hb-outline.hh"
39 #include "hb-ot-cmap-table.hh"
40 #include "hb-ot-glyf-table.hh"
41 #include "hb-ot-cff2-table.hh"
42 #include "hb-ot-cff1-table.hh"
43 #include "hb-ot-hmtx-table.hh"
44 #include "hb-ot-post-table.hh"
45 #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
46 #include "hb-ot-vorg-table.hh"
47 #include "OT/Color/CBDT/CBDT.hh"
48 #include "OT/Color/COLR/COLR.hh"
49 #include "OT/Color/sbix/sbix.hh"
50 #include "OT/Color/svg/svg.hh"
56 * @short_description: OpenType font implementation
59 * Functions for using OpenType fonts with hb_shape(). Note that fonts returned
60 * by hb_font_create() default to using these functions, so most clients would
61 * never need to call these functions directly.
64 using hb_ot_font_cmap_cache_t
= hb_cache_t
<21, 16, 8, true>;
65 using hb_ot_font_advance_cache_t
= hb_cache_t
<24, 16, 8, true>;
67 #ifndef HB_NO_OT_FONT_CMAP_CACHE
68 static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key
;
73 const hb_ot_face_t
*ot_face
;
75 #ifndef HB_NO_OT_FONT_CMAP_CACHE
76 hb_ot_font_cmap_cache_t
*cmap_cache
;
79 /* h_advance caching */
80 mutable hb_atomic_int_t cached_coords_serial
;
81 mutable hb_atomic_ptr_t
<hb_ot_font_advance_cache_t
> advance_cache
;
85 _hb_ot_font_create (hb_font_t
*font
)
87 hb_ot_font_t
*ot_font
= (hb_ot_font_t
*) hb_calloc (1, sizeof (hb_ot_font_t
));
88 if (unlikely (!ot_font
))
91 ot_font
->ot_face
= &font
->face
->table
;
93 #ifndef HB_NO_OT_FONT_CMAP_CACHE
95 auto *cmap_cache
= (hb_ot_font_cmap_cache_t
*) hb_face_get_user_data (font
->face
,
96 &hb_ot_font_cmap_cache_user_data_key
);
99 cmap_cache
= (hb_ot_font_cmap_cache_t
*) hb_malloc (sizeof (hb_ot_font_cmap_cache_t
));
100 if (unlikely (!cmap_cache
)) goto out
;
101 new (cmap_cache
) hb_ot_font_cmap_cache_t ();
102 if (unlikely (!hb_face_set_user_data (font
->face
,
103 &hb_ot_font_cmap_cache_user_data_key
,
108 hb_free (cmap_cache
);
109 cmap_cache
= nullptr;
110 /* Normally we would retry here, but that would
111 * infinite-loop if the face is the empty-face.
112 * Just let it go and this font will be uncached if it
113 * happened to collide with another thread creating the
114 * cache at the same time. */
119 ot_font
->cmap_cache
= cmap_cache
;
126 _hb_ot_font_destroy (void *font_data
)
128 hb_ot_font_t
*ot_font
= (hb_ot_font_t
*) font_data
;
130 auto *cache
= ot_font
->advance_cache
.get_relaxed ();
137 hb_ot_get_nominal_glyph (hb_font_t
*font HB_UNUSED
,
139 hb_codepoint_t unicode
,
140 hb_codepoint_t
*glyph
,
141 void *user_data HB_UNUSED
)
143 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
144 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
145 hb_ot_font_cmap_cache_t
*cmap_cache
= nullptr;
146 #ifndef HB_NO_OT_FONT_CMAP_CACHE
147 cmap_cache
= ot_font
->cmap_cache
;
149 return ot_face
->cmap
->get_nominal_glyph (unicode
, glyph
, cmap_cache
);
153 hb_ot_get_nominal_glyphs (hb_font_t
*font HB_UNUSED
,
156 const hb_codepoint_t
*first_unicode
,
157 unsigned int unicode_stride
,
158 hb_codepoint_t
*first_glyph
,
159 unsigned int glyph_stride
,
160 void *user_data HB_UNUSED
)
162 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
163 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
164 hb_ot_font_cmap_cache_t
*cmap_cache
= nullptr;
165 #ifndef HB_NO_OT_FONT_CMAP_CACHE
166 cmap_cache
= ot_font
->cmap_cache
;
168 return ot_face
->cmap
->get_nominal_glyphs (count
,
169 first_unicode
, unicode_stride
,
170 first_glyph
, glyph_stride
,
175 hb_ot_get_variation_glyph (hb_font_t
*font HB_UNUSED
,
177 hb_codepoint_t unicode
,
178 hb_codepoint_t variation_selector
,
179 hb_codepoint_t
*glyph
,
180 void *user_data HB_UNUSED
)
182 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
183 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
184 hb_ot_font_cmap_cache_t
*cmap_cache
= nullptr;
185 #ifndef HB_NO_OT_FONT_CMAP_CACHE
186 cmap_cache
= ot_font
->cmap_cache
;
188 return ot_face
->cmap
->get_variation_glyph (unicode
,
189 variation_selector
, glyph
,
194 hb_ot_get_glyph_h_advances (hb_font_t
* font
, void* font_data
,
196 const hb_codepoint_t
*first_glyph
,
197 unsigned glyph_stride
,
198 hb_position_t
*first_advance
,
199 unsigned advance_stride
,
200 void *user_data HB_UNUSED
)
203 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
204 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
205 const OT::hmtx_accelerator_t
&hmtx
= *ot_face
->hmtx
;
207 hb_position_t
*orig_first_advance
= first_advance
;
209 #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
210 const OT::HVAR
&HVAR
= *hmtx
.var_table
;
211 const OT::VariationStore
&varStore
= &HVAR
+ HVAR
.varStore
;
212 OT::VariationStore::cache_t
*varStore_cache
= font
->num_coords
* count
>= 128 ? varStore
.create_cache () : nullptr;
214 bool use_cache
= font
->num_coords
;
216 OT::VariationStore::cache_t
*varStore_cache
= nullptr;
217 bool use_cache
= false;
220 hb_ot_font_advance_cache_t
*cache
= nullptr;
224 cache
= ot_font
->advance_cache
.get_acquire ();
225 if (unlikely (!cache
))
227 cache
= (hb_ot_font_advance_cache_t
*) hb_malloc (sizeof (hb_ot_font_advance_cache_t
));
228 if (unlikely (!cache
))
233 new (cache
) hb_ot_font_advance_cache_t
;
235 if (unlikely (!ot_font
->advance_cache
.cmpexch (nullptr, cache
)))
240 ot_font
->cached_coords_serial
.set_release (font
->serial_coords
);
247 for (unsigned int i
= 0; i
< count
; i
++)
249 *first_advance
= font
->em_scale_x (hmtx
.get_advance_with_var_unscaled (*first_glyph
, font
, varStore_cache
));
250 first_glyph
= &StructAtOffsetUnaligned
<hb_codepoint_t
> (first_glyph
, glyph_stride
);
251 first_advance
= &StructAtOffsetUnaligned
<hb_position_t
> (first_advance
, advance_stride
);
256 if (ot_font
->cached_coords_serial
.get_acquire () != (int) font
->serial_coords
)
258 ot_font
->advance_cache
->clear ();
259 ot_font
->cached_coords_serial
.set_release (font
->serial_coords
);
262 for (unsigned int i
= 0; i
< count
; i
++)
266 if (ot_font
->advance_cache
->get (*first_glyph
, &cv
))
270 v
= hmtx
.get_advance_with_var_unscaled (*first_glyph
, font
, varStore_cache
);
271 ot_font
->advance_cache
->set (*first_glyph
, v
);
273 *first_advance
= font
->em_scale_x (v
);
274 first_glyph
= &StructAtOffsetUnaligned
<hb_codepoint_t
> (first_glyph
, glyph_stride
);
275 first_advance
= &StructAtOffsetUnaligned
<hb_position_t
> (first_advance
, advance_stride
);
279 #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
280 OT::VariationStore::destroy_cache (varStore_cache
);
283 if (font
->x_strength
&& !font
->embolden_in_place
)
286 hb_position_t x_strength
= font
->x_scale
>= 0 ? font
->x_strength
: -font
->x_strength
;
287 first_advance
= orig_first_advance
;
288 for (unsigned int i
= 0; i
< count
; i
++)
290 *first_advance
+= *first_advance
? x_strength
: 0;
291 first_advance
= &StructAtOffsetUnaligned
<hb_position_t
> (first_advance
, advance_stride
);
296 #ifndef HB_NO_VERTICAL
298 hb_ot_get_glyph_v_advances (hb_font_t
* font
, void* font_data
,
300 const hb_codepoint_t
*first_glyph
,
301 unsigned glyph_stride
,
302 hb_position_t
*first_advance
,
303 unsigned advance_stride
,
304 void *user_data HB_UNUSED
)
306 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
307 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
308 const OT::vmtx_accelerator_t
&vmtx
= *ot_face
->vmtx
;
310 hb_position_t
*orig_first_advance
= first_advance
;
312 if (vmtx
.has_data ())
314 #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
315 const OT::VVAR
&VVAR
= *vmtx
.var_table
;
316 const OT::VariationStore
&varStore
= &VVAR
+ VVAR
.varStore
;
317 OT::VariationStore::cache_t
*varStore_cache
= font
->num_coords
? varStore
.create_cache () : nullptr;
319 OT::VariationStore::cache_t
*varStore_cache
= nullptr;
322 for (unsigned int i
= 0; i
< count
; i
++)
324 *first_advance
= font
->em_scale_y (-(int) vmtx
.get_advance_with_var_unscaled (*first_glyph
, font
, varStore_cache
));
325 first_glyph
= &StructAtOffsetUnaligned
<hb_codepoint_t
> (first_glyph
, glyph_stride
);
326 first_advance
= &StructAtOffsetUnaligned
<hb_position_t
> (first_advance
, advance_stride
);
329 #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
330 OT::VariationStore::destroy_cache (varStore_cache
);
335 hb_font_extents_t font_extents
;
336 font
->get_h_extents_with_fallback (&font_extents
);
337 hb_position_t advance
= -(font_extents
.ascender
- font_extents
.descender
);
339 for (unsigned int i
= 0; i
< count
; i
++)
341 *first_advance
= advance
;
342 first_glyph
= &StructAtOffsetUnaligned
<hb_codepoint_t
> (first_glyph
, glyph_stride
);
343 first_advance
= &StructAtOffsetUnaligned
<hb_position_t
> (first_advance
, advance_stride
);
347 if (font
->y_strength
&& !font
->embolden_in_place
)
350 hb_position_t y_strength
= font
->y_scale
>= 0 ? font
->y_strength
: -font
->y_strength
;
351 first_advance
= orig_first_advance
;
352 for (unsigned int i
= 0; i
< count
; i
++)
354 *first_advance
+= *first_advance
? y_strength
: 0;
355 first_advance
= &StructAtOffsetUnaligned
<hb_position_t
> (first_advance
, advance_stride
);
361 #ifndef HB_NO_VERTICAL
363 hb_ot_get_glyph_v_origin (hb_font_t
*font
,
365 hb_codepoint_t glyph
,
368 void *user_data HB_UNUSED
)
370 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
371 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
373 *x
= font
->get_glyph_h_advance (glyph
) / 2;
375 const OT::VORG
&VORG
= *ot_face
->VORG
;
376 if (VORG
.has_data ())
381 const OT::vmtx_accelerator_t
&vmtx
= *ot_face
->vmtx
;
382 const OT::VVAR
&VVAR
= *vmtx
.var_table
;
383 if (font
->num_coords
)
384 VVAR
.get_vorg_delta_unscaled (glyph
,
385 font
->coords
, font
->num_coords
,
389 *y
= font
->em_scalef_y (VORG
.get_y_origin (glyph
) + delta
);
393 hb_glyph_extents_t extents
= {0};
394 if (ot_face
->glyf
->get_extents (font
, glyph
, &extents
))
396 const OT::vmtx_accelerator_t
&vmtx
= *ot_face
->vmtx
;
398 if (vmtx
.get_leading_bearing_with_var_unscaled (font
, glyph
, &tsb
))
400 *y
= extents
.y_bearing
+ font
->em_scale_y (tsb
);
404 hb_font_extents_t font_extents
;
405 font
->get_h_extents_with_fallback (&font_extents
);
406 hb_position_t advance
= font_extents
.ascender
- font_extents
.descender
;
407 int diff
= advance
- -extents
.height
;
408 *y
= extents
.y_bearing
+ (diff
>> 1);
412 hb_font_extents_t font_extents
;
413 font
->get_h_extents_with_fallback (&font_extents
);
414 *y
= font_extents
.ascender
;
421 hb_ot_get_glyph_extents (hb_font_t
*font
,
423 hb_codepoint_t glyph
,
424 hb_glyph_extents_t
*extents
,
425 void *user_data HB_UNUSED
)
427 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
428 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
430 #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
431 if (ot_face
->sbix
->get_extents (font
, glyph
, extents
)) return true;
432 if (ot_face
->CBDT
->get_extents (font
, glyph
, extents
)) return true;
434 #if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT)
435 if (ot_face
->COLR
->get_extents (font
, glyph
, extents
)) return true;
437 if (ot_face
->glyf
->get_extents (font
, glyph
, extents
)) return true;
438 #ifndef HB_NO_OT_FONT_CFF
439 if (ot_face
->cff2
->get_extents (font
, glyph
, extents
)) return true;
440 if (ot_face
->cff1
->get_extents (font
, glyph
, extents
)) return true;
446 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
448 hb_ot_get_glyph_name (hb_font_t
*font HB_UNUSED
,
450 hb_codepoint_t glyph
,
451 char *name
, unsigned int size
,
452 void *user_data HB_UNUSED
)
454 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
455 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
457 if (ot_face
->post
->get_glyph_name (glyph
, name
, size
)) return true;
458 #ifndef HB_NO_OT_FONT_CFF
459 if (ot_face
->cff1
->get_glyph_name (glyph
, name
, size
)) return true;
464 hb_ot_get_glyph_from_name (hb_font_t
*font HB_UNUSED
,
466 const char *name
, int len
,
467 hb_codepoint_t
*glyph
,
468 void *user_data HB_UNUSED
)
470 const hb_ot_font_t
*ot_font
= (const hb_ot_font_t
*) font_data
;
471 const hb_ot_face_t
*ot_face
= ot_font
->ot_face
;
473 if (ot_face
->post
->get_glyph_from_name (name
, len
, glyph
)) return true;
474 #ifndef HB_NO_OT_FONT_CFF
475 if (ot_face
->cff1
->get_glyph_from_name (name
, len
, glyph
)) return true;
482 hb_ot_get_font_h_extents (hb_font_t
*font
,
483 void *font_data HB_UNUSED
,
484 hb_font_extents_t
*metrics
,
485 void *user_data HB_UNUSED
)
487 bool ret
= _hb_ot_metrics_get_position_common (font
, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER
, &metrics
->ascender
) &&
488 _hb_ot_metrics_get_position_common (font
, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER
, &metrics
->descender
) &&
489 _hb_ot_metrics_get_position_common (font
, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP
, &metrics
->line_gap
);
492 int y_shift
= font
->y_strength
;
493 if (font
->y_scale
< 0) y_shift
= -y_shift
;
494 metrics
->ascender
+= y_shift
;
499 #ifndef HB_NO_VERTICAL
501 hb_ot_get_font_v_extents (hb_font_t
*font
,
502 void *font_data HB_UNUSED
,
503 hb_font_extents_t
*metrics
,
504 void *user_data HB_UNUSED
)
506 return _hb_ot_metrics_get_position_common (font
, HB_OT_METRICS_TAG_VERTICAL_ASCENDER
, &metrics
->ascender
) &&
507 _hb_ot_metrics_get_position_common (font
, HB_OT_METRICS_TAG_VERTICAL_DESCENDER
, &metrics
->descender
) &&
508 _hb_ot_metrics_get_position_common (font
, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP
, &metrics
->line_gap
);
514 hb_ot_draw_glyph (hb_font_t
*font
,
515 void *font_data HB_UNUSED
,
516 hb_codepoint_t glyph
,
517 hb_draw_funcs_t
*draw_funcs
, void *draw_data
,
520 bool embolden
= font
->x_strength
|| font
->y_strength
;
521 hb_outline_t outline
;
523 { // Need draw_session to be destructed before emboldening.
524 hb_draw_session_t
draw_session (embolden
? hb_outline_recording_pen_get_funcs () : draw_funcs
,
525 embolden
? &outline
: draw_data
, font
->slant_xy
);
526 if (!font
->face
->table
.glyf
->get_path (font
, glyph
, draw_session
))
528 if (!font
->face
->table
.cff2
->get_path (font
, glyph
, draw_session
))
529 if (!font
->face
->table
.cff1
->get_path (font
, glyph
, draw_session
))
536 float x_shift
= font
->embolden_in_place
? 0 : (float) font
->x_strength
/ 2;
537 float y_shift
= (float) font
->y_strength
/ 2;
538 if (font
->x_scale
< 0) x_shift
= -x_shift
;
539 if (font
->y_scale
< 0) y_shift
= -y_shift
;
540 outline
.embolden (font
->x_strength
, font
->y_strength
,
543 outline
.replay (draw_funcs
, draw_data
);
550 hb_ot_paint_glyph (hb_font_t
*font
,
552 hb_codepoint_t glyph
,
553 hb_paint_funcs_t
*paint_funcs
, void *paint_data
,
554 unsigned int palette
,
555 hb_color_t foreground
,
559 if (font
->face
->table
.COLR
->paint_glyph (font
, glyph
, paint_funcs
, paint_data
, palette
, foreground
)) return;
560 if (font
->face
->table
.SVG
->paint_glyph (font
, glyph
, paint_funcs
, paint_data
)) return;
561 #ifndef HB_NO_OT_FONT_BITMAP
562 if (font
->face
->table
.CBDT
->paint_glyph (font
, glyph
, paint_funcs
, paint_data
)) return;
563 if (font
->face
->table
.sbix
->paint_glyph (font
, glyph
, paint_funcs
, paint_data
)) return;
566 if (font
->face
->table
.glyf
->paint_glyph (font
, glyph
, paint_funcs
, paint_data
, foreground
)) return;
568 if (font
->face
->table
.cff2
->paint_glyph (font
, glyph
, paint_funcs
, paint_data
, foreground
)) return;
569 if (font
->face
->table
.cff1
->paint_glyph (font
, glyph
, paint_funcs
, paint_data
, foreground
)) return;
574 static inline void free_static_ot_funcs ();
576 static struct hb_ot_font_funcs_lazy_loader_t
: hb_font_funcs_lazy_loader_t
<hb_ot_font_funcs_lazy_loader_t
>
578 static hb_font_funcs_t
*create ()
580 hb_font_funcs_t
*funcs
= hb_font_funcs_create ();
582 hb_font_funcs_set_nominal_glyph_func (funcs
, hb_ot_get_nominal_glyph
, nullptr, nullptr);
583 hb_font_funcs_set_nominal_glyphs_func (funcs
, hb_ot_get_nominal_glyphs
, nullptr, nullptr);
584 hb_font_funcs_set_variation_glyph_func (funcs
, hb_ot_get_variation_glyph
, nullptr, nullptr);
586 hb_font_funcs_set_font_h_extents_func (funcs
, hb_ot_get_font_h_extents
, nullptr, nullptr);
587 hb_font_funcs_set_glyph_h_advances_func (funcs
, hb_ot_get_glyph_h_advances
, nullptr, nullptr);
588 //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
590 #ifndef HB_NO_VERTICAL
591 hb_font_funcs_set_font_v_extents_func (funcs
, hb_ot_get_font_v_extents
, nullptr, nullptr);
592 hb_font_funcs_set_glyph_v_advances_func (funcs
, hb_ot_get_glyph_v_advances
, nullptr, nullptr);
593 hb_font_funcs_set_glyph_v_origin_func (funcs
, hb_ot_get_glyph_v_origin
, nullptr, nullptr);
597 hb_font_funcs_set_draw_glyph_func (funcs
, hb_ot_draw_glyph
, nullptr, nullptr);
601 hb_font_funcs_set_paint_glyph_func (funcs
, hb_ot_paint_glyph
, nullptr, nullptr);
604 hb_font_funcs_set_glyph_extents_func (funcs
, hb_ot_get_glyph_extents
, nullptr, nullptr);
605 //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
607 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
608 hb_font_funcs_set_glyph_name_func (funcs
, hb_ot_get_glyph_name
, nullptr, nullptr);
609 hb_font_funcs_set_glyph_from_name_func (funcs
, hb_ot_get_glyph_from_name
, nullptr, nullptr);
612 hb_font_funcs_make_immutable (funcs
);
614 hb_atexit (free_static_ot_funcs
);
621 void free_static_ot_funcs ()
623 static_ot_funcs
.free_instance ();
626 static hb_font_funcs_t
*
627 _hb_ot_get_font_funcs ()
629 return static_ot_funcs
.get_unconst ();
634 * hb_ot_font_set_funcs:
635 * @font: #hb_font_t to work upon
637 * Sets the font functions to use when working with @font.
642 hb_ot_font_set_funcs (hb_font_t
*font
)
644 hb_ot_font_t
*ot_font
= _hb_ot_font_create (font
);
645 if (unlikely (!ot_font
))
648 hb_font_set_funcs (font
,
649 _hb_ot_get_font_funcs (),
651 _hb_ot_font_destroy
);