From 2a878b1b7684dac9473f6e64aa01c376d03e7f4f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 7 Mar 2025 17:23:17 -0700 Subject: [PATCH] [font-funcs] Add two new API + hb_font_set_funcs_using() + hb_font_list_funcs() Part of https://github.com/harfbuzz/harfbuzz/issues/5117 --- docs/harfbuzz-sections.txt | 2 + perf/benchmark-font.cc | 77 ++++------------- src/hb-font.cc | 107 ++++++++++++++++++++++++ src/hb-font.h | 6 ++ test/api/test-draw.c | 23 +---- test/api/test-multithread.c | 15 ++-- test/api/test-ot-extents-cff.c | 7 -- test/api/test-ot-face.c | 1 - test/api/test-ot-metrics-tt-var.c | 7 -- test/fuzzing/hb-shape-fuzzer.cc | 1 - test/shape/data/aots/hb-aots-tester.cpp | 1 - test/threads/hb-shape-threads.cc | 32 ++----- util/font-options.hh | 70 ++++------------ 13 files changed, 167 insertions(+), 182 deletions(-) diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 74d2e166e..c37138572 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -458,6 +458,8 @@ hb_font_get_serial hb_font_changed hb_font_set_funcs hb_font_set_funcs_data +hb_font_set_funcs_using +hb_font_list_funcs hb_font_subtract_glyph_origin_for_direction hb_font_funcs_create hb_font_funcs_get_empty diff --git a/perf/benchmark-font.cc b/perf/benchmark-font.cc index deefecf7a..d513b9fe2 100644 --- a/perf/benchmark-font.cc +++ b/perf/benchmark-font.cc @@ -21,8 +21,6 @@ struct test_input_t static test_input_t *tests = default_tests; static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]); -enum backend_t { HARFBUZZ, FREETYPE, FONTATIONS, CORETEXT }; - enum operation_t { nominal_glyphs, @@ -81,7 +79,8 @@ _draw_funcs_create (void) } static void BM_Font (benchmark::State &state, - bool is_var, backend_t backend, operation_t operation, + bool is_var, const char * backend, + operation_t operation, const test_input_t &test_input) { hb_font_t *font; @@ -100,29 +99,12 @@ static void BM_Font (benchmark::State &state, hb_font_set_variations (font, &wght, 1); } - switch (backend) + bool ret = hb_font_set_funcs_using (font, backend); + if (!ret) { - case HARFBUZZ: - hb_ot_font_set_funcs (font); - break; - - case FREETYPE: -#ifdef HAVE_FREETYPE - hb_ft_font_set_funcs (font); -#endif - break; - - case FONTATIONS: -#ifdef HAVE_FONTATIONS - hb_fontations_font_set_funcs (font); -#endif - break; - - case CORETEXT: -#ifdef HAVE_CORETEXT - hb_coretext_font_set_funcs (font); -#endif - break; + state.SkipWithError("Backend failed to initialize for font."); + hb_font_destroy (font); + return; } switch (operation) @@ -210,29 +192,12 @@ static void BM_Font (benchmark::State &state, hb_font_t *font = hb_font_create (face); hb_face_destroy (face); - switch (backend) + bool ret = hb_font_set_funcs_using (font, backend); + if (!ret) { - case HARFBUZZ: - hb_ot_font_set_funcs (font); - break; - - case FREETYPE: -#ifdef HAVE_FREETYPE - hb_ft_font_set_funcs (font); -#endif - break; - - case FONTATIONS: -#ifdef HAVE_FONTATIONS - hb_fontations_font_set_funcs (font); -#endif - break; - - case CORETEXT: -#ifdef HAVE_CORETEXT - hb_coretext_font_set_funcs (font); -#endif - break; + state.SkipWithError("Backend failed to initialize for font."); + hb_font_destroy (font); + return; } hb_buffer_t *buffer = hb_buffer_create (); @@ -252,8 +217,7 @@ static void BM_Font (benchmark::State &state, hb_font_destroy (font); } -static void test_backend (backend_t backend, - const char *backend_name, +static void test_backend (const char *backend, bool variable, operation_t op, const char *op_name, @@ -267,7 +231,7 @@ static void test_backend (backend_t backend, strcat (name, p ? p + 1 : test_input.font_path); strcat (name, variable ? "/var" : ""); strcat (name, "/"); - strcat (name, backend_name); + strcat (name, backend); benchmark::RegisterBenchmark (name, BM_Font, variable, backend, op, test_input) ->Unit(time_unit); @@ -277,6 +241,7 @@ static void test_operation (operation_t op, const char *op_name, benchmark::TimeUnit time_unit) { + const char **supported_backends = hb_font_list_funcs (); for (unsigned i = 0; i < num_tests; i++) { auto& test_input = tests[i]; @@ -284,16 +249,8 @@ static void test_operation (operation_t op, { bool is_var = (bool) variable; - test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input); -#ifdef HAVE_FREETYPE - test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input); -#endif -#ifdef HAVE_FONTATIONS - test_backend (FONTATIONS, "fontations", is_var, op, op_name, time_unit, test_input); -#endif -#ifdef HAVE_CORETEXT - test_backend (CORETEXT, "coretext", is_var, op, op_name, time_unit, test_input); -#endif + for (const char **backend = supported_backends; *backend; backend++) + test_backend (*backend, is_var, op, op_name, time_unit, test_input); } } } diff --git a/src/hb-font.cc b/src/hb-font.cc index 96b79ecca..8d0ff4c8e 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -38,6 +38,19 @@ #include "hb-ot-var-avar-table.hh" #include "hb-ot-var-fvar-table.hh" +#ifndef HB_NO_OT_FONT +#include "hb-ot.h" +#endif +#ifdef HAVE_FREETYPE +#include "hb-ft.h" +#endif +#ifdef HAVE_FONTATIONS +#include "hb-fontations.h" +#endif +#ifdef HAVE_CORETEXT +#include "hb-coretext.h" +#endif + /** * SECTION:hb-font @@ -2292,6 +2305,100 @@ hb_font_set_funcs_data (hb_font_t *font, font->destroy = destroy; } +static struct supported_font_funcs_t { + char name[12]; + void (*func) (hb_font_t *); +} supported_font_funcs[] = +{ + {"ot", hb_ot_font_set_funcs}, +#ifdef HAVE_FREETYPE + {"ft", hb_ft_font_set_funcs}, +#endif +#ifdef HAVE_FONTATIONS + {"fontations",hb_fontations_font_set_funcs}, +#endif +#ifdef HAVE_CORETEXT + {"coretext", hb_coretext_font_set_funcs}, +#endif +}; + +/** + * hb_font_set_funcs_using: + * @font: #hb_font_t to work upon + * @name: The name of the font-functions structure to use + * + * Sets the font-functions structure to use for a font, based on the + * specified name. + * + * If @name is `NULL`, the first functioning font-functions are used. + * + * Return value: `true` if the font-functions was found and set, `false` otherwise + * + * XSince: REPLACEME + **/ +hb_bool_t +hb_font_set_funcs_using (hb_font_t *font, + const char *name) +{ + for (unsigned i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) + if (!name || strcmp (supported_font_funcs[i].name, name) == 0) + { + supported_font_funcs[i].func (font); + if (name || font->klass != hb_font_funcs_get_empty ()) + return true; + } + return false; +} + +static inline void free_static_font_funcs_list (); + +static const char * const nil_font_funcs_list[] = {nullptr}; + +static struct hb_font_funcs_list_lazy_loader_t : hb_lazy_loader_t +{ + static const char ** create () + { + const char **font_funcs_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_font_funcs), sizeof (const char *)); + if (unlikely (!font_funcs_list)) + return nullptr; + + unsigned i; + for (i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) + font_funcs_list[i] = supported_font_funcs[i].name; + font_funcs_list[i] = nullptr; + + hb_atexit (free_static_font_funcs_list); + + return font_funcs_list; + } + static void destroy (const char **l) + { hb_free (l); } + static const char * const * get_null () + { return nil_font_funcs_list; } +} static_font_funcs_list; + +static inline +void free_static_font_funcs_list () +{ + static_font_funcs_list.free_instance (); +} + +/** + * hb_font_list_funcs: + * + * Retrieves the list of font functions supported by HarfBuzz. + * + * Return value: (transfer none) (array zero-terminated=1): an array of + * constant strings + * + * XSince: REPLACEME + **/ +const char ** +hb_font_list_funcs () +{ + return static_font_funcs_list.get_unconst (); +} /** * hb_font_set_scale: diff --git a/src/hb-font.h b/src/hb-font.h index 3c2355af2..478c808e1 100644 --- a/src/hb-font.h +++ b/src/hb-font.h @@ -1052,6 +1052,12 @@ hb_font_set_funcs_data (hb_font_t *font, void *font_data, hb_destroy_func_t destroy); +HB_EXTERN hb_bool_t +hb_font_set_funcs_using (hb_font_t *font, + const char *name); + +HB_EXTERN const char ** +hb_font_list_funcs (void); HB_EXTERN void hb_font_set_scale (hb_font_t *font, diff --git a/test/api/test-draw.c b/test/api/test-draw.c index c956de398..9b608e1af 100644 --- a/test/api/test-draw.c +++ b/test/api/test-draw.c @@ -1077,23 +1077,6 @@ test_hb_draw_immutable (void) hb_draw_funcs_destroy (draw_funcs); } -static void -set_font_funcs (hb_font_t *font, const char *font_funcs_name) -{ - if (strcmp (font_funcs_name, "ft") == 0) -#ifdef HAVE_FREETYPE - hb_ft_font_set_funcs (font); -#else - g_assert_not_reached (); -#endif - else if (strcmp (font_funcs_name, "fontations") == 0) -#ifdef HAVE_FONTATIONS - hb_fontations_font_set_funcs (font); -#else - g_assert_not_reached (); -#endif -} - static void test_hb_draw_funcs (const char* font_funcs_name) { @@ -1105,7 +1088,7 @@ test_hb_draw_funcs (const char* font_funcs_name) { hb_face_t *face = hb_test_open_font_file ("fonts/glyphs.ttf"); hb_font_t *font = hb_font_create (face); - set_font_funcs (font, font_funcs_name); + hb_font_set_funcs_using (font, font_funcs_name); hb_face_destroy (face); { draw_data.consumed = 0; @@ -1124,7 +1107,7 @@ test_hb_draw_funcs (const char* font_funcs_name) { hb_face_t *face = hb_test_open_font_file ("fonts/cff1_flex.otf"); hb_font_t *font = hb_font_create (face); - set_font_funcs (font, font_funcs_name); + hb_font_set_funcs_using (font, font_funcs_name); hb_face_destroy (face); draw_data.consumed = 0; @@ -1165,7 +1148,7 @@ test_hb_draw_compare_ot_funcs (const char* font_funcs_name) hb_font_draw_glyph (font, 1, funcs, &draw_data); draw_data.str[draw_data.consumed] = '\0'; - set_font_funcs (font, font_funcs_name); + hb_font_set_funcs_using (font, font_funcs_name); hb_font_draw_glyph (font, 1, funcs, &draw_data2); draw_data2.str[draw_data2.consumed] = '\0'; diff --git a/test/api/test-multithread.c b/test/api/test-multithread.c index f9460497e..f846416cf 100644 --- a/test/api/test-multithread.c +++ b/test/api/test-multithread.c @@ -93,8 +93,11 @@ thread_func (void *data) } static void -test_body (void) +test_body (const char *backend) { + if (!hb_font_set_funcs_using (font, backend)) + return; + int i; pthread_t *threads = calloc (num_threads, sizeof (pthread_t)); hb_buffer_t **buffers = calloc (num_threads, sizeof (hb_buffer_t *)); @@ -145,13 +148,9 @@ main (int argc, char **argv) ref_buffer = hb_buffer_create (); fill_the_buffer (ref_buffer); - /* Unnecessary, since version 2 it is ot-font by default */ - hb_ot_font_set_funcs (font); - test_body (); - - /* Test hb-ft in multithread */ - hb_ft_font_set_funcs (font); - test_body (); + // TODO Test all backends + test_body ("ot"); + test_body ("ft"); hb_buffer_destroy (ref_buffer); diff --git a/test/api/test-ot-extents-cff.c b/test/api/test-ot-extents-cff.c index e6aeb0d6e..ecebcf96b 100644 --- a/test/api/test-ot-extents-cff.c +++ b/test/api/test-ot-extents-cff.c @@ -37,7 +37,6 @@ test_extents_cff1 (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_glyph_extents_t extents; hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); @@ -55,7 +54,6 @@ test_extents_cff1 (void) hb_font_t *font_j = hb_font_create (face_j); hb_face_destroy (face_j); g_assert (font_j); - hb_ot_font_set_funcs (font_j); hb_bool_t result_j = hb_font_get_glyph_extents (font_j, 3, &extents); g_assert (result_j); @@ -76,7 +74,6 @@ test_extents_cff1_flex (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_glyph_extents_t extents; hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); @@ -98,7 +95,6 @@ test_extents_cff1_seac (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_glyph_extents_t extents; hb_bool_t result = hb_font_get_glyph_extents (font, 3, &extents); /* Agrave */ @@ -128,7 +124,6 @@ test_extents_cff2 (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_glyph_extents_t extents; hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); @@ -160,7 +155,6 @@ test_extents_cff2_vsindex (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_glyph_extents_t extents; float coords[2] = { 800.0f, 50.0f }; @@ -192,7 +186,6 @@ test_extents_cff2_vsindex_named_instance (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_font_set_var_named_instance (font, 6); // 6 (BlackMediumContrast): 900, 50 hb_glyph_extents_t extents; diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c index 6360a186e..7e02bd901 100644 --- a/test/api/test-ot-face.c +++ b/test/api/test-ot-face.c @@ -45,7 +45,6 @@ test_font (hb_font_t *font, hb_codepoint_t cp) char buf[5] = {0}; unsigned int len = 0; hb_glyph_extents_t extents = {0, 0, 0, 0}; - hb_ot_font_set_funcs (font); set = hb_set_create (); hb_face_collect_unicodes (face, set); diff --git a/test/api/test-ot-metrics-tt-var.c b/test/api/test-ot-metrics-tt-var.c index f2587d8a4..43f77a97b 100644 --- a/test/api/test-ot-metrics-tt-var.c +++ b/test/api/test-ot-metrics-tt-var.c @@ -37,7 +37,6 @@ test_extents_tt_var (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_glyph_extents_t extents; hb_bool_t result = hb_font_get_glyph_extents (font, 2, &extents); @@ -69,7 +68,6 @@ test_advance_tt_var_nohvar (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_position_t x, y; hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_LTR, &x, &y); @@ -105,7 +103,6 @@ test_advance_tt_var_hvarvvar (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_position_t x, y; hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_LTR, &x, &y); @@ -141,7 +138,6 @@ test_advance_tt_var_anchor (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_glyph_extents_t extents; hb_bool_t result = hb_font_get_glyph_extents (font, 2, &extents); @@ -173,7 +169,6 @@ test_extents_tt_var_comp (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); hb_glyph_extents_t extents; float coords[1] = { 800.0f }; @@ -215,7 +210,6 @@ test_advance_tt_var_comp_v (void) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); g_assert (font); - hb_ot_font_set_funcs (font); float coords[1] = { 800.0f }; hb_font_set_var_coords_design (font, coords, 1); @@ -239,7 +233,6 @@ test_advance_tt_var_gvar_infer (void) { hb_face_t *face = hb_test_open_font_file ("fonts/TestGVAREight.ttf"); hb_font_t *font = hb_font_create (face); - hb_ot_font_set_funcs (font); hb_face_destroy (face); int coords[6] = {100}; diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc index f14f6518e..b573b6ae5 100644 --- a/test/fuzzing/hb-shape-fuzzer.cc +++ b/test/fuzzing/hb-shape-fuzzer.cc @@ -17,7 +17,6 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) HB_MEMORY_MODE_READONLY, nullptr, nullptr); hb_face_t *face = hb_face_create (blob, 0); hb_font_t *font = hb_font_create (face); - hb_ot_font_set_funcs (font); hb_font_set_scale (font, 12, 12); unsigned num_coords = 0; diff --git a/test/shape/data/aots/hb-aots-tester.cpp b/test/shape/data/aots/hb-aots-tester.cpp index 51958fc55..cfec17def 100644 --- a/test/shape/data/aots/hb-aots-tester.cpp +++ b/test/shape/data/aots/hb-aots-tester.cpp @@ -75,7 +75,6 @@ runTest(const char *testName, unsigned int upem = hb_face_get_upem (face); hb_font_set_scale(font, upem, upem); - hb_ot_font_set_funcs (font); // setup buffer hb_buffer_t *buffer = hb_buffer_create(); diff --git a/test/threads/hb-shape-threads.cc b/test/threads/hb-shape-threads.cc index 93adfc8c8..d72352e8a 100644 --- a/test/threads/hb-shape-threads.cc +++ b/test/threads/hb-shape-threads.cc @@ -11,10 +11,6 @@ #endif #include "hb.h" -#include "hb-ot.h" -#ifdef HAVE_FREETYPE -#include "hb-ft.h" -#endif #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/" @@ -51,8 +47,6 @@ struct test_input_t static test_input_t *tests = default_tests; static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]); -enum backend_t { HARFBUZZ, FREETYPE }; - // https://en.cppreference.com/w/cpp/thread/condition_variable/wait static std::condition_variable cv; static std::mutex cv_m; @@ -105,8 +99,7 @@ static void shape (const test_input_t &input, hb_blob_destroy (text_blob); } -static void test_backend (backend_t backend, - const char *backend_name, +static void test_backend (const char *backend, bool variable, const test_input_t &test_input) { @@ -120,7 +113,7 @@ static void test_backend (backend_t backend, strcat (name, p ? p + 1 : test_input.text_path); strcat (name, variable ? "/var" : ""); strcat (name, "/"); - strcat (name, backend_name); + strcat (name, backend); printf ("Testing %s\n", name); @@ -140,18 +133,8 @@ static void test_backend (backend_t backend, hb_font_set_variations (font, &wght, 1); } - switch (backend) - { - case HARFBUZZ: - hb_ot_font_set_funcs (font); - break; - - case FREETYPE: -#ifdef HAVE_FREETYPE - hb_ft_font_set_funcs (font); -#endif - break; - } + bool ret = hb_font_set_funcs_using (font, backend); + assert (ret); std::vector threads; for (unsigned i = 0; i < num_threads; i++) @@ -200,10 +183,9 @@ int main(int argc, char** argv) { bool is_var = (bool) variable; - test_backend (HARFBUZZ, "hb", is_var, test_input); -#ifdef HAVE_FREETYPE - test_backend (FREETYPE, "ft", is_var, test_input); -#endif + // TODO Test all backends. + test_backend ("ot", is_var, test_input); + test_backend ("ft", is_var, test_input); } } diff --git a/util/font-options.hh b/util/font-options.hh index 88b51ec57..095283e52 100644 --- a/util/font-options.hh +++ b/util/font-options.hh @@ -29,17 +29,6 @@ #include "face-options.hh" -#include -#ifdef HAVE_FREETYPE -#include -#endif -#ifdef HAVE_FONTATIONS -#include -#endif -#ifdef HAVE_CORETEXT -#include -#endif - #define FONT_SIZE_UPEM 0x7FFFFFFF #define FONT_SIZE_NONE 0 @@ -84,24 +73,6 @@ struct font_options_t : face_options_t }; -static struct supported_font_funcs_t { - char name[11]; - void (*func) (hb_font_t *); -} supported_font_funcs[] = -{ - {"ot", hb_ot_font_set_funcs}, -#ifdef HAVE_FREETYPE - {"ft", hb_ft_font_set_funcs}, -#endif -#ifdef HAVE_FONTATIONS - {"fontations",hb_fontations_font_set_funcs}, -#endif -#ifdef HAVE_CORETEXT - {"coretext", hb_coretext_font_set_funcs}, -#endif -}; - - void font_options_t::post_parse (GError **error) { @@ -130,39 +101,35 @@ font_options_t::post_parse (GError **error) hb_font_set_variations (font, variations, num_variations); #endif - void (*set_font_funcs) (hb_font_t *) = nullptr; - if (!font_funcs) + if (font_funcs) { - set_font_funcs = supported_font_funcs[0].func; - } - else - { - for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) - if (0 == g_ascii_strcasecmp (font_funcs, supported_font_funcs[i].name)) - { - set_font_funcs = supported_font_funcs[i].func; - break; - } - if (!set_font_funcs) + if (!hb_font_set_funcs_using (font, font_funcs)) { + const char **supported_font_funcs = hb_font_list_funcs (); + if (unlikely (!supported_font_funcs[0])) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Unknown font function implementation `%s'; no supported values found", + font_funcs); + return; + } GString *s = g_string_new (nullptr); - for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) + for (unsigned i = 0; supported_font_funcs[i]; i++) { if (i) g_string_append_c (s, '/'); - g_string_append (s, supported_font_funcs[i].name); + g_string_append (s, supported_font_funcs[i]); } char *p = g_string_free (s, FALSE); g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Unknown font function implementation `%s'; supported values are: %s; default is %s", font_funcs, p, - supported_font_funcs[0].name); + supported_font_funcs[0]); free (p); return; } } - set_font_funcs (font); #ifdef HAVE_FREETYPE hb_ft_font_set_load_flags (font, ft_load_flags); #endif @@ -309,16 +276,15 @@ font_options_t::add_options (option_parser_t *parser) char *font_funcs_text = nullptr; { - static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0), - "No supported font-funcs found."); + const char **supported_font_funcs = hb_font_list_funcs (); GString *s = g_string_new (nullptr); g_string_printf (s, "Set font functions implementation to use (default: %s)\n Supported font function implementations are: %s", - supported_font_funcs[0].name, - supported_font_funcs[0].name); - for (unsigned int i = 1; i < ARRAY_LENGTH (supported_font_funcs); i++) + supported_font_funcs[0], + supported_font_funcs[0]); + for (unsigned i = 1; supported_font_funcs[i]; i++) { g_string_append_c (s, '/'); - g_string_append (s, supported_font_funcs[i].name); + g_string_append (s, supported_font_funcs[i]); } font_funcs_text = g_string_free (s, FALSE); parser->free_later (font_funcs_text);