From 2a878b1b7684dac9473f6e64aa01c376d03e7f4f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 7 Mar 2025 17:23:17 -0700 Subject: [PATCH 01/23] [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); From c3eac5c0f345ffd2fa99f6ddbb9bbc49aebe4932 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 11:54:15 -0700 Subject: [PATCH 02/23] [test-threads] Test all font-funcs Fontations & Coretext are new and seems to pass. --- test/api/test-multithread.c | 5 ++--- test/threads/hb-shape-threads.cc | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/test/api/test-multithread.c b/test/api/test-multithread.c index f846416cf..52f7cefb9 100644 --- a/test/api/test-multithread.c +++ b/test/api/test-multithread.c @@ -148,9 +148,8 @@ main (int argc, char **argv) ref_buffer = hb_buffer_create (); fill_the_buffer (ref_buffer); - // TODO Test all backends - test_body ("ot"); - test_body ("ft"); + for (const char **font_funcs = hb_font_list_funcs (); *font_funcs; font_funcs++) + test_body (*font_funcs); hb_buffer_destroy (ref_buffer); diff --git a/test/threads/hb-shape-threads.cc b/test/threads/hb-shape-threads.cc index d72352e8a..a99f4ab04 100644 --- a/test/threads/hb-shape-threads.cc +++ b/test/threads/hb-shape-threads.cc @@ -183,9 +183,8 @@ int main(int argc, char** argv) { bool is_var = (bool) variable; - // TODO Test all backends. - test_backend ("ot", is_var, test_input); - test_backend ("ft", is_var, test_input); + for (const char **font_funcs = hb_font_list_funcs (); *font_funcs; font_funcs++) + test_backend (*font_funcs, is_var, test_input); } } From e8ddb4325b856e17aafd7f7d15c5373e00fc812f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 12:13:31 -0700 Subject: [PATCH 03/23] [fontations] Consolidate args a bit --- src/fontations/meson.build | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/fontations/meson.build b/src/fontations/meson.build index d4a9b7ecf..27ed29b42 100644 --- a/src/fontations/meson.build +++ b/src/fontations/meson.build @@ -14,7 +14,14 @@ cargo = find_program('cargo') rustfmt = find_program('rustfmt') rust_flags = '' -cargo_args = [] +cargo_args = [ + '--package', 'harfbuzz_fontations', + '--lib', + '--target-dir', meson.current_build_dir(), + '--manifest-path', meson.current_source_dir() / 'Cargo.toml', + '-Z', 'build-std=std,panic_abort', + '-Z', 'build-std-features=panic_immediate_abort', +] buildtype = get_option('buildtype') if buildtype == 'release' or buildtype == 'debugoptimized' @@ -24,9 +31,6 @@ endif opt_level = get_option('optimization') rust_flags += ' -C opt-level=' + opt_level -cargo_args += ['-Z', 'build-std=std,panic_abort', - '-Z', 'build-std-features=panic_immediate_abort'] - harfbuzz_fontations = custom_target( 'harfbuzz_fontations', input: ['lib.rs', 'Cargo.toml', 'Cargo.lock'], @@ -38,11 +42,8 @@ harfbuzz_fontations = custom_target( command: [ cargo, 'build', ] + cargo_args + [ - '--lib', - '--target-dir', meson.current_build_dir(), '-Z', 'unstable-options', '--artifact-dir', meson.current_build_dir(), - '--manifest-path', meson.current_source_dir() / 'Cargo.toml' ], install: true, install_dir: join_paths(get_option('prefix'), 'lib'), @@ -57,11 +58,8 @@ clippy_fix = run_target( env: ['OUT_DIR=' + meson.current_build_dir()], command: [ cargo, 'clippy', - '--allow-dirty', '--fix', ] + cargo_args + [ - '--lib', '-p', 'harfbuzz_fontations', - '--target-dir', meson.current_build_dir(), - '--manifest-path', meson.current_source_dir() / 'Cargo.toml', + '--allow-dirty', '--fix', ], ) if get_option('tests').enabled() and cargo.found() @@ -72,9 +70,6 @@ if get_option('tests').enabled() and cargo.found() args: [ 'clippy', ] + cargo_args + [ - '--lib', '-p', 'harfbuzz_fontations', - '--target-dir', meson.current_build_dir(), - '--manifest-path', meson.current_source_dir() / 'Cargo.toml', '--', '-D', 'warnings', ], ) From fae9d2ab277c6f692bbfe4f13edd7b736ab28e89 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 12:15:25 -0700 Subject: [PATCH 04/23] [fontations] Add dependencies --- src/fontations/meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fontations/meson.build b/src/fontations/meson.build index 27ed29b42..d93a5c47d 100644 --- a/src/fontations/meson.build +++ b/src/fontations/meson.build @@ -56,6 +56,7 @@ harfbuzz_fontations_dep = declare_dependency( clippy_fix = run_target( 'clippy-fix', env: ['OUT_DIR=' + meson.current_build_dir()], + depends: [hb_rs, harfbuzz_fontations], command: [ cargo, 'clippy', ] + cargo_args + [ @@ -67,6 +68,7 @@ if get_option('tests').enabled() and cargo.found() 'clippy', cargo, env: ['OUT_DIR=' + meson.current_build_dir()], + depends: [hb_rs, harfbuzz_fontations], args: [ 'clippy', ] + cargo_args + [ @@ -78,6 +80,7 @@ endif rustfmt_fix = run_target( 'rustfmt-fix', env: ['OUT_DIR=' + meson.current_build_dir()], + depends: [hb_rs], command: [ rustfmt, '--edition', '2021', @@ -90,6 +93,7 @@ if get_option('tests').enabled() and rustfmt.found() 'rustfmt', rustfmt, env: ['OUT_DIR=' + meson.current_build_dir()], + depends: [hb_rs], args: [ '--check', '--edition', '2021', From 712a403bec7313436378fed6dc235ffd9609c14a Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 12:23:41 -0700 Subject: [PATCH 05/23] [font-funcs-using] Apply review feedback --- src/hb-font.cc | 6 ++++-- src/hb-shape.cc | 4 ++++ test/api/test-draw.c | 9 ++++++--- test/api/test-multithread.c | 4 ++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/hb-font.cc b/src/hb-font.cc index 8d0ff4c8e..dbe915149 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -2389,8 +2389,10 @@ void free_static_font_funcs_list () * * Retrieves the list of font functions supported by HarfBuzz. * - * Return value: (transfer none) (array zero-terminated=1): an array of - * constant strings + * Return value: (transfer none) (array zero-terminated=1): a + * `NULL`-terminated array of supported font functions + * constant string. The returned array is owned by HarfBuzz + * and should not be modified or freed. * * XSince: REPLACEME **/ diff --git a/src/hb-shape.cc b/src/hb-shape.cc index 844f7b9e8..9aa5f9822 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -93,6 +93,10 @@ void free_static_shaper_list () * * Return value: (transfer none) (array zero-terminated=1): an array of * constant strings + * Return value: (transfer none) (array zero-terminated=1): a + * `NULL`-terminated array of supported shapers constant string. + * The returned array is owned by HarfBuzz and should not be + * modified or freed. * * Since: 0.9.2 **/ diff --git a/test/api/test-draw.c b/test/api/test-draw.c index 9b608e1af..a068c78f6 100644 --- a/test/api/test-draw.c +++ b/test/api/test-draw.c @@ -1088,7 +1088,8 @@ 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); - hb_font_set_funcs_using (font, font_funcs_name); + hb_bool_t ret = hb_font_set_funcs_using (font, font_funcs_name); + g_assert (ret); hb_face_destroy (face); { draw_data.consumed = 0; @@ -1107,7 +1108,8 @@ 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); - hb_font_set_funcs_using (font, font_funcs_name); + hb_bool_t ret = hb_font_set_funcs_using (font, font_funcs_name); + g_assert (ret); hb_face_destroy (face); draw_data.consumed = 0; @@ -1148,7 +1150,8 @@ 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'; - hb_font_set_funcs_using (font, font_funcs_name); + hb_bool_t ret = hb_font_set_funcs_using (font, font_funcs_name); + g_assert (ret); 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 52f7cefb9..b83ca6693 100644 --- a/test/api/test-multithread.c +++ b/test/api/test-multithread.c @@ -95,8 +95,8 @@ thread_func (void *data) static void test_body (const char *backend) { - if (!hb_font_set_funcs_using (font, backend)) - return; + bool ret = hb_font_set_funcs_using (font, backend); + g_assert (ret); int i; pthread_t *threads = calloc (num_threads, sizeof (pthread_t)); From 5a12bf417b927a511ad864abd6305899a1bd135b Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 12:31:07 -0700 Subject: [PATCH 06/23] [font-funcs-using] Treat empty string like nullptr --- src/hb-font.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hb-font.cc b/src/hb-font.cc index dbe915149..561f3c06a 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -2330,7 +2330,7 @@ static struct supported_font_funcs_t { * 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. + * If @name is `NULL` or empty string, the first functioning font-functions are used. * * Return value: `true` if the font-functions was found and set, `false` otherwise * @@ -2340,6 +2340,8 @@ hb_bool_t hb_font_set_funcs_using (hb_font_t *font, const char *name) { + if (name && !*name) name = nullptr; + for (unsigned i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) if (!name || strcmp (supported_font_funcs[i].name, name) == 0) { @@ -2347,6 +2349,7 @@ hb_font_set_funcs_using (hb_font_t *font, if (name || font->klass != hb_font_funcs_get_empty ()) return true; } + return false; } From 68b07475a7515166b308c21807f13a57fb68aedb Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 12:41:50 -0700 Subject: [PATCH 07/23] [font-funcs] Support HB_FONT_FUNCS env var --- src/hb-font.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/hb-font.cc b/src/hb-font.cc index 561f3c06a..6d4032aac 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -1867,10 +1867,19 @@ hb_font_create (hb_face_t *face) { hb_font_t *font = _hb_font_create (face); -#ifndef HB_NO_OT_FONT - /* Install our in-house, very lightweight, funcs. */ - hb_ot_font_set_funcs (font); -#endif + static hb_atomic_ptr_t static_funcs_name; + const char *funcs_name = static_funcs_name.get_acquire (); + if (!funcs_name) + { + funcs_name = getenv ("HB_FONT_FUNCS"); + if (!funcs_name) + funcs_name = ""; + if (!static_funcs_name.cmpexch (nullptr, funcs_name)) + funcs_name = static_funcs_name.get_acquire (); + } + + if (unlikely (!hb_font_set_funcs_using (font, funcs_name))) + hb_font_set_funcs_using (font, nullptr); #ifndef HB_NO_VAR if (face && face->index >> 16) @@ -2310,7 +2319,9 @@ static struct supported_font_funcs_t { void (*func) (hb_font_t *); } supported_font_funcs[] = { +#ifndef HB_NO_OT_FONT {"ot", hb_ot_font_set_funcs}, +#endif #ifdef HAVE_FREETYPE {"ft", hb_ft_font_set_funcs}, #endif From 437ce950594241355c577f43a2c65c895daecd7d Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 13:12:15 -0700 Subject: [PATCH 08/23] [util] Add --list-font-funcs --- util/font-options.hh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/util/font-options.hh b/util/font-options.hh index 095283e52..0b3e098e3 100644 --- a/util/font-options.hh +++ b/util/font-options.hh @@ -143,6 +143,18 @@ font_options_t::post_parse (GError **error) } } +static G_GNUC_NORETURN gboolean +list_font_funcs (const char *name G_GNUC_UNUSED, + const char *arg G_GNUC_UNUSED, + gpointer data G_GNUC_UNUSED, + GError **error G_GNUC_UNUSED) +{ + for (const char **funcs = hb_font_list_funcs (); *funcs; funcs++) + g_printf ("%s\n", *funcs); + + exit(0); +} + #ifndef HB_NO_VAR static gboolean parse_variations (const char *name G_GNUC_UNUSED, @@ -315,6 +327,8 @@ font_options_t::add_options (option_parser_t *parser) {"font-slant", 0, font_size_flags, G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"}, {"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, font_funcs_text, "impl"}, + {"list-font-funcs", 0, G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, (gpointer) &list_font_funcs, "List available font functions and quit", nullptr}, {"sub-font", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &this->sub_font, "Create a sub-font (default: false)", "boolean"}, {"ft-load-flags", 0, 0, G_OPTION_ARG_INT, &this->ft_load_flags, "Set FreeType load-flags (default: 2)", "integer"}, From 43ff0f73ccaa41e4dc68ba992506108868b1ac60 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 13:30:10 -0700 Subject: [PATCH 09/23] [fontations] Relax dependency numbers --- src/fontations/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fontations/Cargo.toml b/src/fontations/Cargo.toml index 33b6ba40c..0eb031695 100644 --- a/src/fontations/Cargo.toml +++ b/src/fontations/Cargo.toml @@ -3,8 +3,8 @@ name = "harfbuzz_fontations" edition = "2021" [dependencies] -read-fonts = "0.27.2" -skrifa = "0.28.1" +read-fonts = "0.27" +skrifa = "0.28" [lib] name = "harfbuzz_fontations" From 50ea460b93bd0081c69ccad2ae25fc8392a30bfb Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 8 Mar 2025 16:07:44 -0700 Subject: [PATCH 10/23] Review --- src/hb-shape.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hb-shape.cc b/src/hb-shape.cc index 9aa5f9822..c62f8c6bc 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -91,8 +91,6 @@ void free_static_shaper_list () * * Retrieves the list of shapers supported by HarfBuzz. * - * Return value: (transfer none) (array zero-terminated=1): an array of - * constant strings * Return value: (transfer none) (array zero-terminated=1): a * `NULL`-terminated array of supported shapers constant string. * The returned array is owned by HarfBuzz and should not be From 39ade99d4779706169e32d8b63fd734ec16e96a6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 01:25:52 -0700 Subject: [PATCH 11/23] [face] Two new APIs: + hb_face_create_from_file_or_fail_using() + hb_face_list_loaders() --- src/hb-face.cc | 105 +++++++++++++++++++++++++++++++++++++++++++ src/hb-face.h | 9 ++++ src/hb-font.cc | 4 +- util/face-options.hh | 91 +++++++++++-------------------------- util/font-options.hh | 21 ++++++--- 5 files changed, 158 insertions(+), 72 deletions(-) diff --git a/src/hb-face.cc b/src/hb-face.cc index 002bb37d4..190a9c52f 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -34,6 +34,13 @@ #include "hb-ot-face.hh" #include "hb-ot-cmap-table.hh" +#ifdef HAVE_FREETYPE +#include "hb-ft.h" +#endif +#ifdef HAVE_CORETEXT +#include "hb-coretext.h" +#endif + /** * SECTION:hb-face @@ -320,6 +327,104 @@ hb_face_create_from_file_or_fail (const char *file_name, } #endif +static struct supported_face_loaders_t { + char name[9]; + hb_face_t * (*func) (const char *font_file, unsigned face_index); +} supported_face_loaders[] = +{ +#ifndef HB_NO_OPEN + {"ot", hb_face_create_from_file_or_fail}, +#endif +#ifdef HAVE_FREETYPE + {"ft", hb_ft_face_create_from_file_or_fail}, +#endif +#ifdef HAVE_CORETEXT + {"coretext", hb_coretext_face_create_from_file_or_fail}, +#endif +}; + +/** + * hb_face_create_from_file_or_fail_using: + * @file_name: A font filename + * @index: The index of the face within the file + * @loader_name: (nullable): The name of the loader to use, or `NULL` + * + * A thin wrapper around the face loader functions registered with HarfBuzz. + * If @loader_name is `NULL`, the first available loader is used. + * + * Return value: (transfer full): The new face object, or `NULL` if + * the file cannot be read or the loader fails to load the face. + * + * XSince: REPLACEME + **/ +hb_face_t * +hb_face_create_from_file_or_fail_using (const char *file_name, + unsigned int index, + const char *loader_name) +{ + if (loader_name && !*loader_name) + loader_name = nullptr; + for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) + { + if (!loader_name || !strcmp (supported_face_loaders[i].name, loader_name)) + return supported_face_loaders[i].func (file_name, index); + } + return nullptr; +} + +static inline void free_static_face_loader_list (); + +static const char * const nil_face_loader_list[] = {nullptr}; + +static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t +{ + static const char ** create () + { + const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *)); + if (unlikely (!face_loader_list)) + return nullptr; + + unsigned i; + for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) + face_loader_list[i] = supported_face_loaders[i].name; + face_loader_list[i] = nullptr; + + hb_atexit (free_static_face_loader_list); + + return face_loader_list; + } + static void destroy (const char **l) + { hb_free (l); } + static const char * const * get_null () + { return nil_face_loader_list; } +} static_face_loader_list; + +static inline +void free_static_face_loader_list () +{ + static_face_loader_list.free_instance (); +} + +/** + * hb_face_list_loaders: + * + * Retrieves the list of face loaders supported by HarfBuzz. + * + * Return value: (transfer none) (array zero-terminated=1): a + * `NULL`-terminated array of supported face loaders + * constant strings. The returned array is owned by HarfBuzz + * and should not be modified or freed. + * + * XSince: REPLACEME + **/ +const char ** +hb_face_list_loaders () +{ + return static_face_loader_list.get_unconst (); +} + + /** * hb_face_get_empty: * diff --git a/src/hb-face.h b/src/hb-face.h index afc198547..c59ec0c4b 100644 --- a/src/hb-face.h +++ b/src/hb-face.h @@ -67,6 +67,15 @@ HB_EXTERN hb_face_t * hb_face_create_from_file_or_fail (const char *file_name, unsigned int index); +HB_EXTERN hb_face_t * +hb_face_create_from_file_or_fail_using (const char *file_name, + unsigned int index, + const char *loader_name); + +HB_EXTERN const char ** +hb_face_list_loaders (void); + + /** * hb_reference_table_func_t: * @face: an #hb_face_t to reference table for diff --git a/src/hb-font.cc b/src/hb-font.cc index 6d4032aac..5568dd8fc 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -2336,7 +2336,7 @@ static struct supported_font_funcs_t { /** * hb_font_set_funcs_using: * @font: #hb_font_t to work upon - * @name: The name of the font-functions structure to use + * @name: The name of the font-functions structure to use, or `NULL` * * Sets the font-functions structure to use for a font, based on the * specified name. @@ -2405,7 +2405,7 @@ void free_static_font_funcs_list () * * Return value: (transfer none) (array zero-terminated=1): a * `NULL`-terminated array of supported font functions - * constant string. The returned array is owned by HarfBuzz + * constant strings. The returned array is owned by HarfBuzz * and should not be modified or freed. * * XSince: REPLACEME diff --git a/util/face-options.hh b/util/face-options.hh index 929ec4c38..5192421f3 100644 --- a/util/face-options.hh +++ b/util/face-options.hh @@ -29,13 +29,6 @@ #include "options.hh" -#ifdef HAVE_FREETYPE -#include -#endif -#ifdef HAVE_CORETEXT -#include -#endif - struct face_options_t { ~face_options_t () @@ -74,20 +67,6 @@ struct face_options_t face_options_t::cache_t face_options_t::cache {}; -static struct supported_face_loaders_t { - char name[9]; - hb_face_t * (*func) (const char *font_file, unsigned face_index); -} supported_face_loaders[] = -{ - {"ot", hb_face_create_from_file_or_fail}, -#ifdef HAVE_FREETYPE - {"ft", hb_ft_face_create_from_file_or_fail}, -#endif -#ifdef HAVE_CORETEXT - {"coretext", hb_coretext_face_create_from_file_or_fail}, -#endif -}; - void face_options_t::post_parse (GError **error) { @@ -112,46 +91,12 @@ face_options_t::post_parse (GError **error) #endif } - hb_face_t * (*face_load) (const char *file_name, unsigned face_index) = nullptr; - if (!face_loader) - { - face_load = supported_face_loaders[0].func; - } - else - { - for (unsigned int i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) - if (0 == g_ascii_strcasecmp (face_loader, supported_face_loaders[i].name)) - { - face_load = supported_face_loaders[i].func; - break; - } - if (!face_load) - { - GString *s = g_string_new (nullptr); - for (unsigned int i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) - { - if (i) - g_string_append_c (s, '/'); - g_string_append (s, supported_face_loaders[i].name); - } - g_string_append_c (s, '\n'); - char *p = g_string_free (s, FALSE); - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Unknown face loader `%s'; supported values are: %s; default is %s", - face_loader, - p, - supported_face_loaders[0].name); - free (p); - return; - } - } - if (!cache.font_path || 0 != strcmp (cache.font_path, font_path) || cache.face_index != face_index) { hb_face_destroy (cache.face); - cache.face = face_load (font_path, face_index); + cache.face = hb_face_create_from_file_or_fail_using (font_path, face_index, face_loader); cache.face_index = face_index; free ((char *) cache.font_path); @@ -168,21 +113,37 @@ face_options_t::post_parse (GError **error) face = cache.face; } +static G_GNUC_NORETURN gboolean +list_face_loaders (const char *name G_GNUC_UNUSED, + const char *arg G_GNUC_UNUSED, + gpointer data G_GNUC_UNUSED, + GError **error G_GNUC_UNUSED) +{ + for (const char **funcs = hb_face_list_loaders (); *funcs; funcs++) + g_printf ("%s\n", *funcs); + + exit(0); +} + void face_options_t::add_options (option_parser_t *parser) { char *face_loaders_text = nullptr; { - static_assert ((ARRAY_LENGTH_CONST (supported_face_loaders) > 0), - "No supported face-loaders found."); + const char **supported_face_loaders = hb_face_list_loaders (); GString *s = g_string_new (nullptr); - g_string_printf (s, "Set face loader to use (default: %s)\n Supported face loaders are: %s", - supported_face_loaders[0].name, - supported_face_loaders[0].name); - for (unsigned int i = 1; i < ARRAY_LENGTH (supported_face_loaders); i++) + if (unlikely (!supported_face_loaders)) + g_string_printf (s, "Set face loader to use (default: none)\n No supported face loaders found"); + else { - g_string_append_c (s, '/'); - g_string_append (s, supported_face_loaders[i].name); + g_string_printf (s, "Set face loader to use (default: %s)\n Supported face loaders are: %s", + supported_face_loaders[0], + supported_face_loaders[0]); + for (unsigned i = 1; supported_face_loaders[i]; i++) + { + g_string_append_c (s, '/'); + g_string_append (s, supported_face_loaders[i]); + } } face_loaders_text = g_string_free (s, FALSE); parser->free_later (face_loaders_text); @@ -193,6 +154,8 @@ face_options_t::add_options (option_parser_t *parser) {"font-file", 0, 0, G_OPTION_ARG_STRING, &this->font_file, "Set font file-name", "filename"}, {"face-index", 'y', 0, G_OPTION_ARG_INT, &this->face_index, "Set face index (default: 0)", "index"}, {"face-loader", 0, 0, G_OPTION_ARG_STRING, &this->face_loader, face_loaders_text, "loader"}, + {"list-face-loaders",0, G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, (gpointer) &list_face_loaders, "List available face loaders and quit", nullptr}, {nullptr} }; parser->add_group (entries, diff --git a/util/font-options.hh b/util/font-options.hh index 0b3e098e3..bacd7bc9b 100644 --- a/util/font-options.hh +++ b/util/font-options.hh @@ -29,6 +29,10 @@ #include "face-options.hh" +#ifdef HAVE_FREETYPE +#include +#endif + #define FONT_SIZE_UPEM 0x7FFFFFFF #define FONT_SIZE_NONE 0 @@ -290,13 +294,18 @@ font_options_t::add_options (option_parser_t *parser) { 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], - supported_font_funcs[0]); - for (unsigned i = 1; supported_font_funcs[i]; i++) + if (unlikely (!supported_font_funcs[0])) + g_string_printf (s, "Set font functions implementation to use (default: none)\n No supported font function implementations found"); + else { - g_string_append_c (s, '/'); - g_string_append (s, supported_font_funcs[i]); + g_string_printf (s, "Set font functions implementation to use (default: %s)\n Supported font function implementations are: %s", + 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]); + } } font_funcs_text = g_string_free (s, FALSE); parser->free_later (font_funcs_text); From 9d05b03f83ac4064a15cf5e59fd8acfc952867ce Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 01:34:37 -0700 Subject: [PATCH 12/23] [font] Add HB_FONT_FUNCS work into hb_font_set_funcs_using() --- src/hb-font.cc | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/hb-font.cc b/src/hb-font.cc index 5568dd8fc..2c79c0d83 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -1867,19 +1867,7 @@ hb_font_create (hb_face_t *face) { hb_font_t *font = _hb_font_create (face); - static hb_atomic_ptr_t static_funcs_name; - const char *funcs_name = static_funcs_name.get_acquire (); - if (!funcs_name) - { - funcs_name = getenv ("HB_FONT_FUNCS"); - if (!funcs_name) - funcs_name = ""; - if (!static_funcs_name.cmpexch (nullptr, funcs_name)) - funcs_name = static_funcs_name.get_acquire (); - } - - if (unlikely (!hb_font_set_funcs_using (font, funcs_name))) - hb_font_set_funcs_using (font, nullptr); + hb_font_set_funcs_using (font, nullptr); #ifndef HB_NO_VAR if (face && face->index >> 16) @@ -2341,7 +2329,9 @@ static struct supported_font_funcs_t { * Sets the font-functions structure to use for a font, based on the * specified name. * - * If @name is `NULL` or empty string, the first functioning font-functions are used. + * If @name is `NULL` or empty string, the default (first) functioning font-functions + * are used. This default can be changed by setting the `HB_FONT_FUNCS` environment + * variable to the name of the desired font-functions. * * Return value: `true` if the font-functions was found and set, `false` otherwise * @@ -2351,8 +2341,25 @@ hb_bool_t hb_font_set_funcs_using (hb_font_t *font, const char *name) { + bool retry = false; + + if (!name || !*name) + { + static hb_atomic_ptr_t static_funcs_name; + name = static_funcs_name.get_acquire (); + if (!name) + { + name = getenv ("HB_FONT_FUNCS"); + if (!name) + name = ""; + if (!static_funcs_name.cmpexch (nullptr, name)) + name = static_funcs_name.get_acquire (); + } + retry = true; + } if (name && !*name) name = nullptr; +retry: for (unsigned i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) if (!name || strcmp (supported_font_funcs[i].name, name) == 0) { @@ -2361,6 +2368,13 @@ hb_font_set_funcs_using (hb_font_t *font, return true; } + if (retry) + { + retry = false; + name = nullptr; + goto retry; + } + return false; } From 6b9d9f7259595f7b6fd98204559224be9e791412 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 01:40:23 -0700 Subject: [PATCH 13/23] [face] Add HB_FACE_LOADER env var --- perf/hb-benchmark.hh | 17 +---------------- src/hb-face.cc | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/perf/hb-benchmark.hh b/perf/hb-benchmark.hh index 28860476d..c976831c0 100644 --- a/perf/hb-benchmark.hh +++ b/perf/hb-benchmark.hh @@ -56,22 +56,7 @@ static inline hb_face_t * hb_benchmark_face_create_from_file_or_fail (const char *font_path, unsigned face_index) { - const char *loader = getenv ("HB_FACE_LOADER"); - if (loader && !*loader) - loader = nullptr; - -#ifdef HAVE_FREETYPE - if (loader && !strcmp (loader, "ft")) - return hb_ft_face_create_from_file_or_fail (font_path, face_index); -#endif -#ifdef HAVE_CORETEXT - if (loader && !strcmp (loader, "coretext")) - return hb_coretext_face_create_from_file_or_fail (font_path, face_index); -#endif - if (!loader || !strcmp (loader, "ot")) - return hb_face_create_from_file_or_fail (font_path, face_index); - - assert (false); + return hb_face_create_from_file_or_fail_using (font_path, face_index, nullptr); } HB_END_DECLS diff --git a/src/hb-face.cc b/src/hb-face.cc index 190a9c52f..a738e9c28 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -352,6 +352,10 @@ static struct supported_face_loaders_t { * A thin wrapper around the face loader functions registered with HarfBuzz. * If @loader_name is `NULL`, the first available loader is used. * + * For example, the FreeType ("ft") loader might be able to load + * .woff and .woff2 files if FreeType is built with those features, + * whereas the OpenType ("ot") loader will not. + * * Return value: (transfer full): The new face object, or `NULL` if * the file cannot be read or the loader fails to load the face. * @@ -360,15 +364,40 @@ static struct supported_face_loaders_t { hb_face_t * hb_face_create_from_file_or_fail_using (const char *file_name, unsigned int index, - const char *loader_name) + const char *name) { - if (loader_name && !*loader_name) - loader_name = nullptr; + bool retry = false; + + if (!name || !*name) + { + static hb_atomic_ptr_t static_funcs_name; + name = static_funcs_name.get_acquire (); + if (!name) + { + name = getenv ("HB_FACE_LOADER"); + if (!name) + name = ""; + if (!static_funcs_name.cmpexch (nullptr, name)) + name = static_funcs_name.get_acquire (); + } + retry = true; + } + if (name && !*name) name = nullptr; + +retry: for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) { - if (!loader_name || !strcmp (supported_face_loaders[i].name, loader_name)) + if (!name || !strcmp (supported_face_loaders[i].name, name)) return supported_face_loaders[i].func (file_name, index); } + + if (retry) + { + retry = false; + name = nullptr; + goto retry; + } + return nullptr; } From 2ecc68c12fb811f696af0de280ec0e96bab4b7d4 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 01:46:07 -0700 Subject: [PATCH 14/23] [face] Fix HB_LEAN build --- src/hb-face.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-face.cc b/src/hb-face.cc index a738e9c28..4a783f74f 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -325,7 +325,6 @@ hb_face_create_from_file_or_fail (const char *file_name, return face; } -#endif static struct supported_face_loaders_t { char name[9]; @@ -452,6 +451,7 @@ hb_face_list_loaders () { return static_face_loader_list.get_unconst (); } +#endif /** From 5cf1fa3adddfdad74f820867aa11da561fbee117 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 01:47:23 -0700 Subject: [PATCH 15/23] [face] Fix docs --- docs/harfbuzz-sections.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index c37138572..5eb940ee8 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -365,6 +365,8 @@ hb_face_t hb_face_create hb_face_create_or_fail hb_face_create_from_file_or_fail +hb_face_create_from_file_or_fail_using +hb_face_list_loaders hb_reference_table_func_t hb_face_create_for_tables hb_face_get_empty From 402f89cb79001082534d034e28b8bf4f5a83f170 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 01:52:03 -0700 Subject: [PATCH 16/23] [face] Rename a variable --- src/hb-face.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/hb-face.cc b/src/hb-face.cc index 4a783f74f..a403f086f 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -363,37 +363,37 @@ static struct supported_face_loaders_t { hb_face_t * hb_face_create_from_file_or_fail_using (const char *file_name, unsigned int index, - const char *name) + const char *loader_name) { bool retry = false; - if (!name || !*name) + if (!loader_name || !*loader_name) { static hb_atomic_ptr_t static_funcs_name; - name = static_funcs_name.get_acquire (); - if (!name) + loader_name = static_funcs_name.get_acquire (); + if (!loader_name) { - name = getenv ("HB_FACE_LOADER"); - if (!name) - name = ""; - if (!static_funcs_name.cmpexch (nullptr, name)) - name = static_funcs_name.get_acquire (); + loader_name = getenv ("HB_FACE_LOADER"); + if (!loader_name) + loader_name = ""; + if (!static_funcs_name.cmpexch (nullptr, loader_name)) + loader_name = static_funcs_name.get_acquire (); } retry = true; } - if (name && !*name) name = nullptr; + if (loader_name && !*loader_name) loader_name = nullptr; retry: for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) { - if (!name || !strcmp (supported_face_loaders[i].name, name)) + if (!loader_name || !strcmp (supported_face_loaders[i].name, loader_name)) return supported_face_loaders[i].func (file_name, index); } if (retry) { retry = false; - name = nullptr; + loader_name = nullptr; goto retry; } From a83faa061c6fea251a6878cae0bb02d8d5949d75 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 03:07:45 -0600 Subject: [PATCH 17/23] [ft] Automatically pick up font serial changes Part of https://github.com/harfbuzz/harfbuzz/issues/5124 --- src/hb-ft.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/hb-ft.cc b/src/hb-ft.cc index efb4b7d24..786b94b23 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -478,6 +478,8 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_position_t *orig_first_advance = first_advance; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; @@ -561,6 +563,8 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Fixed v; float y_mult; @@ -614,6 +618,8 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; float x_mult, y_mult; @@ -658,6 +664,8 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Vector kerningv; @@ -677,6 +685,8 @@ hb_ft_get_glyph_extents (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; float x_mult, y_mult; @@ -749,6 +759,8 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; @@ -826,6 +838,8 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; float y_mult; @@ -916,6 +930,8 @@ hb_ft_draw_glyph (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; @@ -990,6 +1006,8 @@ hb_ft_paint_glyph (hb_font_t *font, void *user_data) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; @@ -1456,6 +1474,10 @@ hb_ft_font_changed (hb_font_t *font) * variation-axis settings on the @font. * This call is fast if nothing has changed on @font. * + * Note that as of version REPLACEME, calling this function is not necessary, + * as HarfBuzz will automatically detect changes to the font and update + * the underlying FT_Face as needed. + * * Return value: true if changed, false otherwise * * Since: 4.4.0 From 6ae7ef065978499eb38d2fcfa9e87bb1e512983f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 03:19:22 -0600 Subject: [PATCH 18/23] [ft] See if I can make tsan happy --- src/hb-ft.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 786b94b23..f5fd7cae0 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -213,9 +213,11 @@ _hb_ft_hb_font_check_changed (hb_font_t *font, { if (font->serial != ft_font->cached_serial) { + ft_font->lock.lock (); _hb_ft_hb_font_changed (font, ft_font->ft_face); ft_font->advance_cache.clear (); ft_font->cached_serial = font->serial; + ft_font->lock.unlock (); return true; } return false; From aa268fc8ef84ec353f2ef0c3878d0ba8dcd54303 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 03:31:01 -0600 Subject: [PATCH 19/23] [font/ft] See if tsan is happy with atomic_int_t serials --- src/hb-atomic.hh | 2 ++ src/hb-font.cc | 15 ++++++++++----- src/hb-font.hh | 5 +++-- src/hb-ft.cc | 4 ++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh index 121c463a5..ce6ac38d8 100644 --- a/src/hb-atomic.hh +++ b/src/hb-atomic.hh @@ -186,6 +186,8 @@ struct hb_atomic_int_t hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; } operator int () const { return get_relaxed (); } + int operator ++ (int) { return inc (); } + int operator -- (int) { return dec (); } void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); } diff --git a/src/hb-font.cc b/src/hb-font.cc index 2c79c0d83..526c96bbb 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -2744,7 +2744,8 @@ hb_font_set_variations (hb_font_t *font, if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; + font->serial++; + font->serial_coords = font->serial; if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE) { @@ -2814,7 +2815,8 @@ hb_font_set_variation (hb_font_t *font, if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; + font->serial++; + font->serial_coords = font->serial; // TODO Share some of this code with set_variations() @@ -2886,7 +2888,8 @@ hb_font_set_var_coords_design (hb_font_t *font, if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; + font->serial++; + font->serial_coords = font->serial; int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr; float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; @@ -2924,7 +2927,8 @@ hb_font_set_var_named_instance (hb_font_t *font, if (font->instance_index == instance_index) return; - font->serial_coords = ++font->serial; + font->serial++; + font->serial_coords = font->serial; font->instance_index = instance_index; hb_font_set_variations (font, nullptr, 0); @@ -2971,7 +2975,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font, if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; + font->serial++; + font->serial_coords = font->serial; int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr; int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr; diff --git a/src/hb-font.hh b/src/hb-font.hh index 4c8190b0d..a8e6f7b0a 100644 --- a/src/hb-font.hh +++ b/src/hb-font.hh @@ -32,6 +32,7 @@ #include "hb.hh" #include "hb-face.hh" +#include "hb-atomic.hh" #include "hb-shaper.hh" @@ -105,8 +106,8 @@ DECLARE_NULL_INSTANCE (hb_font_funcs_t); struct hb_font_t { hb_object_header_t header; - unsigned int serial; - unsigned int serial_coords; + hb_atomic_int_t serial; + hb_atomic_int_t serial_coords; hb_font_t *parent; hb_face_t *face; diff --git a/src/hb-ft.cc b/src/hb-ft.cc index f5fd7cae0..fdb021dd8 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -101,7 +101,7 @@ struct hb_ft_font_t mutable hb_mutex_t lock; /* Protects members below. */ FT_Face ft_face; - mutable unsigned cached_serial; + mutable hb_atomic_int_t cached_serial; mutable hb_ft_advance_cache_t advance_cache; }; @@ -118,7 +118,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; - ft_font->cached_serial = (unsigned) -1; + ft_font->cached_serial = -1; new (&ft_font->advance_cache) hb_ft_advance_cache_t; return ft_font; From 7791f50e3ac43df31e210f275f4ee62390a5bdf6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 03:34:28 -0600 Subject: [PATCH 20/23] [ft] Use a lock-guard --- src/hb-ft.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hb-ft.cc b/src/hb-ft.cc index fdb021dd8..a5a11ce24 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -213,11 +213,10 @@ _hb_ft_hb_font_check_changed (hb_font_t *font, { if (font->serial != ft_font->cached_serial) { - ft_font->lock.lock (); + hb_lock_t lock (ft_font->lock); _hb_ft_hb_font_changed (font, ft_font->ft_face); ft_font->advance_cache.clear (); ft_font->cached_serial = font->serial; - ft_font->lock.unlock (); return true; } return false; From 1e812e43b3c0a54ffe5f72be66026d6c65eb99c1 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 03:39:52 -0600 Subject: [PATCH 21/23] [ft] Another try at making tsan happy maybe --- src/hb-ft.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ft.cc b/src/hb-ft.cc index a5a11ce24..3159a9ec3 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -216,7 +216,7 @@ _hb_ft_hb_font_check_changed (hb_font_t *font, hb_lock_t lock (ft_font->lock); _hb_ft_hb_font_changed (font, ft_font->ft_face); ft_font->advance_cache.clear (); - ft_font->cached_serial = font->serial; + ft_font->cached_serial.set_release (font->serial.get_acquire ()); return true; } return false; From 9e639e676a754af87a10430f3f0a948e7de9f110 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 05:10:50 -0600 Subject: [PATCH 22/23] [face] Review --- src/hb-face.cc | 3 ++- src/hb-font.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hb-face.cc b/src/hb-face.cc index a403f086f..e35aa1caf 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -349,7 +349,8 @@ static struct supported_face_loaders_t { * @loader_name: (nullable): The name of the loader to use, or `NULL` * * A thin wrapper around the face loader functions registered with HarfBuzz. - * If @loader_name is `NULL`, the first available loader is used. + * If @loader_name is `NULL` or the empty string, the first available loader + * is used. * * For example, the FreeType ("ft") loader might be able to load * .woff and .woff2 files if FreeType is built with those features, diff --git a/src/hb-font.cc b/src/hb-font.cc index 526c96bbb..79655e29a 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -2329,7 +2329,7 @@ static struct supported_font_funcs_t { * Sets the font-functions structure to use for a font, based on the * specified name. * - * If @name is `NULL` or empty string, the default (first) functioning font-functions + * If @name is `NULL` or the empty string, the default (first) functioning font-functions * are used. This default can be changed by setting the `HB_FONT_FUNCS` environment * variable to the name of the desired font-functions. * From ec6f99c5eab4e683e24001fdabb34b9410a9d02a Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Mar 2025 05:18:13 -0600 Subject: [PATCH 23/23] [fontations] Give clippy test more time --- src/fontations/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fontations/meson.build b/src/fontations/meson.build index d93a5c47d..d21b9af4c 100644 --- a/src/fontations/meson.build +++ b/src/fontations/meson.build @@ -74,6 +74,7 @@ if get_option('tests').enabled() and cargo.found() ] + cargo_args + [ '--', '-D', 'warnings', ], + timeout: 120, ) endif