From fa4fc2901a6025f22919cca4484fec2ffc4cb552 Mon Sep 17 00:00:00 2001 From: 6ziv Date: Wed, 29 Oct 2025 02:22:52 +0800 Subject: [PATCH 1/6] Let HarfBuzz inject its function pointers into FreeType --- CMakeLists.txt | 15 +++++++++++++-- builds/unix/configure.raw | 15 ++++++++++++++- include/freetype/config/ftoption.h | 20 ++++++++++++++++++++ meson.build | 7 +++++++ meson_options.txt | 2 +- src/autofit/afmodule.c | 23 +++++++++++++++++++++-- src/autofit/afmodule.h | 5 +++-- src/autofit/ft-hb.c | 10 ++++++++++ src/autofit/ft-hb.h | 9 +++++++-- 9 files changed, 96 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce70f6b5e..8e58f6b94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,6 +205,9 @@ option(FT_DISABLE_HARFBUZZ cmake_dependent_option(FT_DYNAMIC_HARFBUZZ "Load HarfBuzz library dynamically at runtime, if possible." ON "NOT FT_DISABLE_HARFBUZZ" OFF) +cmake_dependent_option(FT_USE_HARFBUZZ_CALLBACKS + "Let HarfBuzz library inject callback methods at runtime." OFF + "NOT FT_DISABLE_HARFBUZZ;NOT FT_DYNAMIC_HARFBUZZ" OFF) cmake_dependent_option(FT_REQUIRE_HARFBUZZ "Require HarfBuzz for improving auto-hinting of OpenType fonts." OFF "NOT FT_DISABLE_HARFBUZZ" OFF) @@ -272,10 +275,14 @@ if (NOT FT_DISABLE_HARFBUZZ) endif() endif() endif() + elseif(FT_USE_HARFBUZZ_CALLBACKS) + set(FT_HARFBUZZ_CALLBACKS_ENABLED TRUE) endif() if (FT_DYNAMIC_HARFBUZZ_ENABLED) message(STATUS "Enabled dynamic loading of HarfBuzz library at runtime.") + elseif (FT_HARFBUZZ_CALLBACKS_ENABLED) + message(STATUS "Enable HarfBuzz to inject callbacks into FreeType.") elseif (FT_REQUIRE_HARFBUZZ) find_package(HarfBuzz ${HARFBUZZ_MIN_VERSION} REQUIRED) else () @@ -373,7 +380,7 @@ if (PNG_FOUND) "/\\* +(#define +FT_CONFIG_OPTION_USE_PNG) +\\*/" "\\1" FTOPTION_H "${FTOPTION_H}") endif () -if (HARFBUZZ_FOUND OR FT_DYNAMIC_HARFBUZZ_ENABLED) +if (HARFBUZZ_FOUND OR FT_DYNAMIC_HARFBUZZ_ENABLED OR FT_HARFBUZZ_CALLBACKS_ENABLED) string(REGEX REPLACE "/\\* +(#define +FT_CONFIG_OPTION_USE_HARFBUZZ) +\\*/" "\\1" FTOPTION_H "${FTOPTION_H}") @@ -381,6 +388,10 @@ if (HARFBUZZ_FOUND OR FT_DYNAMIC_HARFBUZZ_ENABLED) string(REGEX REPLACE "/\\* +(#define +FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC) +\\*/" "\\1" FTOPTION_H "${FTOPTION_H}") + elseif (FT_HARFBUZZ_CALLBACKS_ENABLED) + string(REGEX REPLACE + "/\\* +(#define +FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS) +\\*/" "\\1" + FTOPTION_H "${FTOPTION_H}") endif () endif () if (BROTLIDEC_FOUND) @@ -572,7 +583,7 @@ if (FT_DYNAMIC_HARFBUZZ_ENABLED AND FT_NEED_LIBDL) target_link_libraries(freetype PRIVATE dl) list(APPEND PKGCONFIG_LIBS_PRIVATE " -ldl") endif () -if (HarfBuzz_FOUND AND (NOT FT_DYNAMIC_HARFBUZZ_ENABLED)) +if (HarfBuzz_FOUND AND (NOT FT_DYNAMIC_HARFBUZZ_ENABLED) AND (NOT FT_HARFBUZZ_CALLBACKS_ENABLED)) target_link_libraries(freetype PRIVATE HarfBuzz::HarfBuzz) list(APPEND PKGCONFIG_REQUIRES_PRIVATE "harfbuzz >= ${HARFBUZZ_MIN_VERSION}") endif () diff --git a/builds/unix/configure.raw b/builds/unix/configure.raw index 45a9be6e4..3b1e62a8b 100644 --- a/builds/unix/configure.raw +++ b/builds/unix/configure.raw @@ -441,7 +441,7 @@ fi # check for system libharfbuzz AC_ARG_WITH([harfbuzz], - [AS_HELP_STRING([--with-harfbuzz=@<:@yes|dynamic|no|auto@:>@], + [AS_HELP_STRING([--with-harfbuzz=@<:@yes|dynamic|no|callbacks|auto@:>@], [improve auto-hinting of OpenType fonts @<:@default=auto@:>@])], [], [with_harfbuzz=auto]) @@ -505,6 +505,14 @@ if test x"$have_harfbuzz" = xno; then ;; esac fi + + +have_harfbuzz_callbacks=no +if test x"$have_harfbuzz" = xno; then + if test x"$with_harfbuzz" = xcallbacks; then + have_harfbuzz_callbacks=yes + have_harfbuzz="yes (callbacks)" + fi fi if test x"$have_harfbuzz" = xno; then @@ -1165,6 +1173,11 @@ if test "$have_harfbuzz_dynamic" != no; then else ftoption_unset FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC fi +if test "$have_harfbuzz_callbacks" != no; then + ftoption_set FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS +else + ftoption_unset FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS +fi if test "$have_brotli" != no; then CFLAGS="$CFLAGS $BROTLI_CFLAGS" LDFLAGS="$LDFLAGS $BROTLI_LIBS" diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index 493418689..195d0ba2e 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -317,6 +317,26 @@ FT_BEGIN_HEADER */ /* #define FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + /************************************************************************** + * + * HarfBuzz callbacks support. + * + * Define this macro if you want the HarfBuzz library to inject callback + * functions to FreeType + * + * This option has no effect if `FT_CONFIG_OPTION_USE_HARFBUZZ` is not + * defined. + * + * When this option is enabled, FreeType will not load or link to the + * HarfBuzz library. Instead, the HarfBuzz library is expected to set + * use property 'harfbuzz-callbacks' to pass callback functions into + * FreeType. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS */ /************************************************************************** * diff --git a/meson.build b/meson.build index 09382fbef..42f244517 100644 --- a/meson.build +++ b/meson.build @@ -388,6 +388,13 @@ if not harfbuzz_dep.found() and \ endif endif +if harfbuzz_opt == 'callbacks' + ftoption_command += [ + '--enable=FT_CONFIG_OPTION_USE_HARFBUZZ', + '--enable=FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS', + ] +endif + if harfbuzz_opt == 'disabled' or harfbuzz_opt == 'auto' harfbuzz_opt = 'NO' endif diff --git a/meson_options.txt b/meson_options.txt index c9e48356d..3f79b6044 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -24,7 +24,7 @@ option('bzip2', option('harfbuzz', type: 'combo', - choices: ['auto', 'enabled', 'dynamic', 'disabled'], + choices: ['auto', 'enabled', 'dynamic', 'disabled', 'callbacks'], value: 'auto', description: 'Use Harfbuzz library to improve auto-hinting;' + ' if available, many glyphs not directly addressable' diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c index 22d85a889..875691b7c 100644 --- a/src/autofit/afmodule.c +++ b/src/autofit/afmodule.c @@ -275,7 +275,16 @@ return error; } - +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) +#if defined ( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) +#error "Can not set both dynamic harfbuzz and injected harfbuzz callbacks" +#endif + else if ( !ft_strcmp( property_name, "harfbuzz-callbacks" ) ) + { + module->hb_funcs = (ft_hb_funcs_t*)value; + } +#endif FT_TRACE2(( "af_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); @@ -362,7 +371,17 @@ return error; } - +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) +#if defined ( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) +#error "Can not set both dynamic harfbuzz and injected harfbuzz callbacks" +#endif + else if ( !ft_strcmp( property_name, "harfbuzz-callbacks" ) ) + { + ft_hb_funcs_t **val = (ft_hb_funcs_t **)value; + *val = module->hb_funcs; + } +#endif FT_TRACE2(( "af_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); diff --git a/src/autofit/afmodule.h b/src/autofit/afmodule.h index c62421ef6..5de6d7306 100644 --- a/src/autofit/afmodule.h +++ b/src/autofit/afmodule.h @@ -41,8 +41,9 @@ FT_BEGIN_HEADER FT_Bool no_stem_darkening; FT_Int darken_params[8]; -#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ - defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + ( defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) || \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) ) ft_hb_funcs_t* hb_funcs; #endif diff --git a/src/autofit/ft-hb.c b/src/autofit/ft-hb.c index 3c145d046..9c1e1b09f 100644 --- a/src/autofit/ft-hb.c +++ b/src/autofit/ft-hb.c @@ -179,6 +179,14 @@ #else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) + FT_LOCAL_DEF( FT_Bool ) + ft_hb_enabled( struct AF_FaceGlobalsRec_ *globals ) + { + return globals->module->hb_funcs != NULL; + } +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS*/ FT_LOCAL_DEF( FT_Bool ) ft_hb_enabled( struct AF_FaceGlobalsRec_ *globals ) { @@ -191,6 +199,8 @@ #endif } +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS */ + #endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ diff --git a/src/autofit/ft-hb.h b/src/autofit/ft-hb.h index 95914deb8..c8f180134 100644 --- a/src/autofit/ft-hb.h +++ b/src/autofit/ft-hb.h @@ -29,7 +29,8 @@ FT_BEGIN_HEADER # include "ft-hb-types.h" -# ifdef FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC +# if defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) || \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) # define HB_EXTERN( ret, name, args ) \ typedef ret (*ft_ ## name ## _func_t) args; @@ -44,6 +45,8 @@ FT_BEGIN_HEADER # undef HB_EXTERN } ft_hb_funcs_t; +# ifdef FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC + struct AF_ModuleRec_; FT_LOCAL( void ) @@ -52,9 +55,11 @@ FT_BEGIN_HEADER FT_LOCAL( void ) ft_hb_funcs_done( struct AF_ModuleRec_ *af_module ); +# endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + # define hb( x ) globals->module->hb_funcs->hb_ ## x -# else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ +# else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC && !FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS*/ # define HB_EXTERN( ret, name, args ) \ ret name args; From ad211e558b12fd16ea1e3d45716f0c8002440367 Mon Sep 17 00:00:00 2001 From: 6ziv Date: Wed, 29 Oct 2025 02:46:36 +0800 Subject: [PATCH 2/6] move exposed ft-hb interface to public include directory --- .../freetype}/ft-hb-decls.h | 0 include/freetype/ft-hb-functype.h | 46 +++++++++++++++++++ .../freetype}/ft-hb-types.h | 0 meson.build | 3 ++ src/autofit/ft-hb.c | 2 +- src/autofit/ft-hb.h | 17 +------ src/autofit/rules.mk | 3 +- 7 files changed, 53 insertions(+), 18 deletions(-) rename {src/autofit => include/freetype}/ft-hb-decls.h (100%) create mode 100644 include/freetype/ft-hb-functype.h rename {src/autofit => include/freetype}/ft-hb-types.h (100%) diff --git a/src/autofit/ft-hb-decls.h b/include/freetype/ft-hb-decls.h similarity index 100% rename from src/autofit/ft-hb-decls.h rename to include/freetype/ft-hb-decls.h diff --git a/include/freetype/ft-hb-functype.h b/include/freetype/ft-hb-functype.h new file mode 100644 index 000000000..0fafb64a9 --- /dev/null +++ b/include/freetype/ft-hb-functype.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * ft-hb.h + * + * FreeType-HarfBuzz bridge (specification). + * + * Copyright (C) 2025 by + * 6ziv. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + * + * Originally located in src/autofit/ft-hb.h + * Move to a public header so that external projects can rely on this. + * + */ + +#ifndef FT_HB_FUNCTYPE_H +#define FT_HB_FUNCTYPE_H + +#include +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) || \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) + +#define HB_EXTERN( ret, name, args ) \ + typedef ret (*ft_ ## name ## _func_t) args; +#include +#undef HB_EXTERN + +typedef struct ft_hb_funcs_t +{ + + #define HB_EXTERN( ret, name, args ) \ + ft_ ## name ## _func_t name; +#include +#undef HB_EXTERN + +} ft_hb_funcs_t; + +#endif + +#endif /* FT_HB_FUNCTYPE_H */ \ No newline at end of file diff --git a/src/autofit/ft-hb-types.h b/include/freetype/ft-hb-types.h similarity index 100% rename from src/autofit/ft-hb-types.h rename to include/freetype/ft-hb-types.h diff --git a/meson.build b/meson.build index 42f244517..fe70d93db 100644 --- a/meson.build +++ b/meson.build @@ -183,6 +183,9 @@ ft2_public_headers = files([ 'include/freetype/ttnameid.h', 'include/freetype/tttables.h', 'include/freetype/tttags.h', + 'include/freetype/ft-hb-types.h', + 'include/freetype/ft-hb-decls.h', + 'include/freetype/ft-hb-functype.h' ]) ft2_config_headers = files([ diff --git a/src/autofit/ft-hb.c b/src/autofit/ft-hb.c index 9c1e1b09f..12e7f5ea1 100644 --- a/src/autofit/ft-hb.c +++ b/src/autofit/ft-hb.c @@ -137,7 +137,7 @@ if ( !funcs->name ) \ goto Fail; \ } -#include "ft-hb-decls.h" +#include #undef HB_EXTERN #undef DLSYM diff --git a/src/autofit/ft-hb.h b/src/autofit/ft-hb.h index c8f180134..1893d1373 100644 --- a/src/autofit/ft-hb.h +++ b/src/autofit/ft-hb.h @@ -27,24 +27,11 @@ FT_BEGIN_HEADER #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ -# include "ft-hb-types.h" +# include # if defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) || \ defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) -# define HB_EXTERN( ret, name, args ) \ - typedef ret (*ft_ ## name ## _func_t) args; -# include "ft-hb-decls.h" -# undef HB_EXTERN - - typedef struct ft_hb_funcs_t - { -# define HB_EXTERN( ret, name, args ) \ - ft_ ## name ## _func_t name; -# include "ft-hb-decls.h" -# undef HB_EXTERN - } ft_hb_funcs_t; - # ifdef FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC struct AF_ModuleRec_; @@ -63,7 +50,7 @@ FT_BEGIN_HEADER # define HB_EXTERN( ret, name, args ) \ ret name args; -# include "ft-hb-decls.h" +# include # undef HB_EXTERN # define hb( x ) hb_ ## x diff --git a/src/autofit/rules.mk b/src/autofit/rules.mk index 03fb5a5ed..52e6a00a8 100644 --- a/src/autofit/rules.mk +++ b/src/autofit/rules.mk @@ -53,8 +53,7 @@ AUTOF_DRV_H := $(AUTOF_DRV_SRC:%c=%h) \ $(AUTOF_DIR)/afstyles.h \ $(AUTOF_DIR)/aftypes.h \ $(AUTOF_DIR)/afws-decl.h \ - $(AUTOF_DIR)/afws-iter.h \ - $(AUTOF_DIR)/ft-hb-decls.h + $(AUTOF_DIR)/afws-iter.h # AUTOF driver object(s) From 007b8bdec1ca8e3bc37cfe40ed270b2a334f71d6 Mon Sep 17 00:00:00 2001 From: 6ziv Date: Wed, 29 Oct 2025 02:56:03 +0800 Subject: [PATCH 3/6] Rename HB_EXTERN to FT_HB_EXTERN to avoid confusion. --- include/freetype/ft-hb-decls.h | 70 +++++++++++++++---------------- include/freetype/ft-hb-functype.h | 8 ++-- src/autofit/ft-hb.c | 4 +- src/autofit/ft-hb.h | 4 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/include/freetype/ft-hb-decls.h b/include/freetype/ft-hb-decls.h index 032d4d37a..db6976dd4 100644 --- a/include/freetype/ft-hb-decls.h +++ b/include/freetype/ft-hb-decls.h @@ -27,90 +27,90 @@ /* All HarfBuzz function declarations used by FreeType, taken */ /* from various public HarfBuzz header files. The wrapper macro */ - /* `HB_EXTERN` is defined in `ft-hb.h`. */ + /* `FT_HB_EXTERN` is defined in `ft-hb.h`. */ /* hb-blob.h */ -HB_EXTERN(hb_blob_t *, +FT_HB_EXTERN(hb_blob_t *, hb_blob_create,(const char *data, unsigned int length, hb_memory_mode_t mode, void *user_data, hb_destroy_func_t destroy)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_blob_destroy,(hb_blob_t *blob)) /* hb-buffer.h */ -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_buffer_add_utf8,(hb_buffer_t *buffer, const char *text, int text_length, unsigned int item_offset, int item_length)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_buffer_clear_contents,(hb_buffer_t *buffer)) -HB_EXTERN(hb_buffer_t *, +FT_HB_EXTERN(hb_buffer_t *, hb_buffer_create,(void)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_buffer_destroy,(hb_buffer_t *buffer)) -HB_EXTERN(hb_glyph_info_t *, +FT_HB_EXTERN(hb_glyph_info_t *, hb_buffer_get_glyph_infos,(hb_buffer_t *buffer, unsigned int *length)) -HB_EXTERN(hb_glyph_position_t *, +FT_HB_EXTERN(hb_glyph_position_t *, hb_buffer_get_glyph_positions,(hb_buffer_t *buffer, unsigned int *length)) -HB_EXTERN(unsigned int, +FT_HB_EXTERN(unsigned int, hb_buffer_get_length,(const hb_buffer_t *buffer)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_buffer_guess_segment_properties,(hb_buffer_t *buffer)) /* hb-face.h */ -HB_EXTERN(hb_face_t *, +FT_HB_EXTERN(hb_face_t *, hb_face_create,(hb_blob_t *blob, unsigned int index)) -HB_EXTERN(hb_face_t *, +FT_HB_EXTERN(hb_face_t *, hb_face_create_for_tables,(hb_reference_table_func_t reference_table_func, void *user_data, hb_destroy_func_t destroy)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_face_destroy,(hb_face_t *face)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_face_set_index,(hb_face_t *face, unsigned int index)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_face_set_upem,(hb_face_t *face, unsigned int upem)) /* hb-font.h */ -HB_EXTERN(hb_font_t *, +FT_HB_EXTERN(hb_font_t *, hb_font_create,(hb_face_t *face)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_font_destroy,(hb_font_t *font)) -HB_EXTERN(hb_face_t *, +FT_HB_EXTERN(hb_face_t *, hb_font_get_face,(hb_font_t *font)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_font_set_scale,(hb_font_t *font, int x_scale, int y_scale)) @@ -118,7 +118,7 @@ hb_font_set_scale,(hb_font_t *font, /* hb-ot-layout.h */ -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_ot_layout_collect_lookups,(hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *scripts, @@ -126,7 +126,7 @@ hb_ot_layout_collect_lookups,(hb_face_t *face, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_ot_layout_lookup_collect_glyphs,(hb_face_t *face, hb_tag_t table_tag, unsigned int lookup_index, @@ -135,14 +135,14 @@ hb_ot_layout_lookup_collect_glyphs,(hb_face_t *face, hb_set_t *glyphs_after, /* OUT. May be NULL */ hb_set_t *glyphs_output /* OUT. May be NULL */)) -HB_EXTERN(hb_bool_t, +FT_HB_EXTERN(hb_bool_t, hb_ot_layout_lookup_would_substitute,(hb_face_t *face, unsigned int lookup_index, const hb_codepoint_t *glyphs, unsigned int glyphs_length, hb_bool_t zero_context)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_ot_tags_from_script_and_language,(hb_script_t script, hb_language_t language, unsigned int *script_count /* IN/OUT */, @@ -153,48 +153,48 @@ hb_ot_tags_from_script_and_language,(hb_script_t script, /* hb-set.h */ -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_set_add,(hb_set_t *set, hb_codepoint_t codepoint)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_set_clear,(hb_set_t *set)) -HB_EXTERN(hb_set_t *, +FT_HB_EXTERN(hb_set_t *, hb_set_create,(void)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_set_destroy,(hb_set_t *set)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_set_del,(hb_set_t *set, hb_codepoint_t codepoint)) -HB_EXTERN(hb_bool_t, +FT_HB_EXTERN(hb_bool_t, hb_set_has,(const hb_set_t *set, hb_codepoint_t codepoint)) -HB_EXTERN(hb_bool_t, +FT_HB_EXTERN(hb_bool_t, hb_set_is_empty,(const hb_set_t *set)) -HB_EXTERN(hb_bool_t, +FT_HB_EXTERN(hb_bool_t, hb_set_next,(const hb_set_t *set, hb_codepoint_t *codepoint)) -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_set_subtract,(hb_set_t *set, const hb_set_t *other)) /* hb-shape.h */ -HB_EXTERN(void, +FT_HB_EXTERN(void, hb_shape,(hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features)) -HB_EXTERN(hb_bool_t, +FT_HB_EXTERN(hb_bool_t, hb_version_atleast,(unsigned int major, unsigned int minor, unsigned int micro)) diff --git a/include/freetype/ft-hb-functype.h b/include/freetype/ft-hb-functype.h index 0fafb64a9..01bdd197f 100644 --- a/include/freetype/ft-hb-functype.h +++ b/include/freetype/ft-hb-functype.h @@ -26,18 +26,18 @@ #if defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) || \ defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) -#define HB_EXTERN( ret, name, args ) \ +#define FT_HB_EXTERN( ret, name, args ) \ typedef ret (*ft_ ## name ## _func_t) args; #include -#undef HB_EXTERN +#undef FT_HB_EXTERN typedef struct ft_hb_funcs_t { - #define HB_EXTERN( ret, name, args ) \ + #define FT_HB_EXTERN( ret, name, args ) \ ft_ ## name ## _func_t name; #include -#undef HB_EXTERN +#undef FT_HB_EXTERN } ft_hb_funcs_t; diff --git a/src/autofit/ft-hb.c b/src/autofit/ft-hb.c index 12e7f5ea1..5c184398e 100644 --- a/src/autofit/ft-hb.c +++ b/src/autofit/ft-hb.c @@ -131,14 +131,14 @@ goto Fail; /* Load all symbols we use. */ -#define HB_EXTERN( ret, name, args ) \ +#define FT_HB_EXTERN( ret, name, args ) \ { \ funcs->name = DLSYM( lib, name ); \ if ( !funcs->name ) \ goto Fail; \ } #include -#undef HB_EXTERN +#undef FT_HB_EXTERN #undef DLSYM diff --git a/src/autofit/ft-hb.h b/src/autofit/ft-hb.h index 1893d1373..ddfa76923 100644 --- a/src/autofit/ft-hb.h +++ b/src/autofit/ft-hb.h @@ -48,10 +48,10 @@ FT_BEGIN_HEADER # else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC && !FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS*/ -# define HB_EXTERN( ret, name, args ) \ +# define FT_HB_EXTERN( ret, name, args ) \ ret name args; # include -# undef HB_EXTERN +# undef FT_HB_EXTERN # define hb( x ) hb_ ## x From 8356dc1db4e77153ed78f2b09c18d72973d78480 Mon Sep 17 00:00:00 2001 From: 6ziv Date: Wed, 29 Oct 2025 04:51:14 +0800 Subject: [PATCH 4/6] indent --- meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index fe70d93db..fd0e04701 100644 --- a/meson.build +++ b/meson.build @@ -393,9 +393,9 @@ endif if harfbuzz_opt == 'callbacks' ftoption_command += [ - '--enable=FT_CONFIG_OPTION_USE_HARFBUZZ', - '--enable=FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS', - ] + '--enable=FT_CONFIG_OPTION_USE_HARFBUZZ', + '--enable=FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS', + ] endif if harfbuzz_opt == 'disabled' or harfbuzz_opt == 'auto' From f8d56061e5c4053d57727c7ccf880dd716e169b8 Mon Sep 17 00:00:00 2001 From: 6ziv Date: Wed, 29 Oct 2025 05:52:11 +0800 Subject: [PATCH 5/6] config calling convention --- CMakeLists.txt | 16 ++++++++++++- builds/unix/configure.raw | 14 +++++++++++ include/freetype/config/ftoption.h | 38 ++++++++++++++++++++++++++++++ include/freetype/ft-hb-functype.h | 28 ++++++++++++++++++++-- meson.build | 14 +++++++++++ meson_options.txt | 9 +++++++ 6 files changed, 116 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e58f6b94..bff771ab5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -211,6 +211,12 @@ cmake_dependent_option(FT_USE_HARFBUZZ_CALLBACKS cmake_dependent_option(FT_REQUIRE_HARFBUZZ "Require HarfBuzz for improving auto-hinting of OpenType fonts." OFF "NOT FT_DISABLE_HARFBUZZ" OFF) +cmake_dependent_option(FT_USE_HARFBUZZ_CALLING_CONVENTION_CDECL + "use HarfBuzz library as cdecl." OFF + "NOT FT_DISABLE_HARFBUZZ" OFF) +cmake_dependent_option(FT_USE_HARFBUZZ_CALLING_CONVENTION_STDCALL + "use HarfBuzz library as stdcall." OFF + "NOT FT_DISABLE_HARFBUZZ;NOT FT_USE_HARFBUZZ_CALLING_CONVENTION_CDECL" OFF) option(FT_DISABLE_BROTLI "Disable support of compressed WOFF2 fonts." OFF) @@ -278,7 +284,6 @@ if (NOT FT_DISABLE_HARFBUZZ) elseif(FT_USE_HARFBUZZ_CALLBACKS) set(FT_HARFBUZZ_CALLBACKS_ENABLED TRUE) endif() - if (FT_DYNAMIC_HARFBUZZ_ENABLED) message(STATUS "Enabled dynamic loading of HarfBuzz library at runtime.") elseif (FT_HARFBUZZ_CALLBACKS_ENABLED) @@ -393,6 +398,15 @@ if (HARFBUZZ_FOUND OR FT_DYNAMIC_HARFBUZZ_ENABLED OR FT_HARFBUZZ_CALLBACKS_ENABL "/\\* +(#define +FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS) +\\*/" "\\1" FTOPTION_H "${FTOPTION_H}") endif () + if (FT_USE_HARFBUZZ_CALLING_CONVENTION_CDECL) + string(REGEX REPLACE + "/\\* +(#define +FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_CDECL) +\\*/" "\\1" + FTOPTION_H "${FTOPTION_H}") + elseif(FT_USE_HARFBUZZ_CALLING_CONVENTION_STDCALL) + string(REGEX REPLACE + "/\\* +(#define +FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_STDCALL) +\\*/" "\\1" + FTOPTION_H "${FTOPTION_H}") + endif() endif () if (BROTLIDEC_FOUND) string(REGEX REPLACE diff --git a/builds/unix/configure.raw b/builds/unix/configure.raw index 3b1e62a8b..625dcf36d 100644 --- a/builds/unix/configure.raw +++ b/builds/unix/configure.raw @@ -1178,6 +1178,20 @@ if test "$have_harfbuzz_callbacks" != no; then else ftoption_unset FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS fi +AC_ARG_WITH([harfbuzz-calling-convention], + [AS_HELP_STRING([--with-harfbuzz-calling-convention=@<:@auto|cdecl|stdcall@:>@], + [calling convention of harfbuzz library @<:@default=auto@:>@])], + [], [with_harfbuzz_calling_convention=auto]) +if test x"$with_harfbuzz_calling_convention" = xcdecl; then + ftoption_set FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_CDECL +else + ftoption_unset FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_CDECL +fi +if test x"$with_harfbuzz_calling_convention" = xstdcall; then + ftoption_set FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_STDCALL +else + ftoption_unset FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_STDCALL +fi if test "$have_brotli" != no; then CFLAGS="$CFLAGS $BROTLI_CFLAGS" LDFLAGS="$LDFLAGS $BROTLI_LIBS" diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index 195d0ba2e..eb057788b 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -338,6 +338,44 @@ FT_BEGIN_HEADER */ /* #define FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS */ + /************************************************************************** + * + * HarfBuzz dynamic/callbacks calling convention. + * + * Define this macro if the HarfBuzz library is using cdecl calling + * convention + * + * This option has no effect if not using harfbuzz mode 'dynamic' or + * 'callbacks'. + * + * When this option is enabled, FreeType will consider loaded or + * injected HarfBuzz-related functions as __cdecl. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_CDECL */ + + /************************************************************************** + * + * HarfBuzz dynamic/callbacks calling convention. + * + * Define this macro if the HarfBuzz library is using stdcall calling + * convention + * + * This option has no effect if not using harfbuzz mode 'dynamic' or + * 'callbacks'. + * + * When this option is enabled, FreeType will consider loaded or + * injected HarfBuzz-related functions as __stdcall. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_STDCALL */ + /************************************************************************** * * Brotli support. diff --git a/include/freetype/ft-hb-functype.h b/include/freetype/ft-hb-functype.h index 01bdd197f..615461076 100644 --- a/include/freetype/ft-hb-functype.h +++ b/include/freetype/ft-hb-functype.h @@ -1,6 +1,6 @@ /**************************************************************************** * - * ft-hb.h + * ft-hb-functype.h * * FreeType-HarfBuzz bridge (specification). * @@ -26,8 +26,32 @@ #if defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) || \ defined( FT_CONFIG_OPTION_USE_HARFBUZZ_CALLBACKS ) +#include + +#if defined(FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_CDECL) + +#if defined( __GNUC__ ) +#define FT_HB_CALLBACK +#elif defined( _MSC_VER) +#define FT_HB_CALLBACK __cdecl +#endif + +#elif defined(FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_STDCALL) /* FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_CDECL */ + +#if defined( __GNUC__ ) +#define FT_HB_CALLBACK __attribute__((stdcall)) +#elif defined( _MSC_VER) +#define FT_HB_CALLBACK __stdcall +#endif + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_CDECL */ + +#ifndef FT_HB_CALLBACK +#define FT_HB_CALLBACK +#endif + #define FT_HB_EXTERN( ret, name, args ) \ - typedef ret (*ft_ ## name ## _func_t) args; + typedef ret (FT_HB_CALLBACK *ft_ ## name ## _func_t) args; #include #undef FT_HB_EXTERN diff --git a/meson.build b/meson.build index fd0e04701..5faa60b33 100644 --- a/meson.build +++ b/meson.build @@ -402,6 +402,20 @@ if harfbuzz_opt == 'disabled' or harfbuzz_opt == 'auto' harfbuzz_opt = 'NO' endif +if harfbuzz_opt == 'dynamic' or harfbuzz_opt == 'callbacks' + harfbuzz_calling_convention = get_option('harfbuzz_calling_convention') + if harfbuzz_calling_convention == 'cdecl' + ftoption_command += [ + '--enable=FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_CDECL', + ] + endif + if harfbuzz_calling_convention == 'stdcall' + ftoption_command += [ + '--enable=FT_CONFIG_OPTION_USE_HARFBUZZ_CALLING_CONVENTION_STDCALL', + ] + endif +endif + # Brotli decompression support. brotli_dep = dependency('libbrotlidec', required: get_option('brotli')) diff --git a/meson_options.txt b/meson_options.txt index 3f79b6044..63bb11eaa 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -30,6 +30,15 @@ option('harfbuzz', + ' if available, many glyphs not directly addressable' + ' by a font\'s character map will be hinted also') +option('harfbuzz-calling-convention', + type: 'combo', + choices: ['auto', 'stdcall', 'cdecl'], + value: 'auto', + description: 'Calling-convention for HarfBuzz. Only used when using' + + ' harfbuzz=\'dynamic\' or harfbuzz=\'callbacks\'. If' + + ' unspecified or set to \'auto\', no specifier will' + + ' be added.') + option('mmap', type: 'feature', value: 'auto', From d9c0d0ac1545efec323e70f71ad6a4ac4e48e2a7 Mon Sep 17 00:00:00 2001 From: 6ziv Date: Wed, 29 Oct 2025 12:51:01 +0800 Subject: [PATCH 6/6] fix typo --- meson_options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson_options.txt b/meson_options.txt index 63bb11eaa..eda4f3f32 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -30,7 +30,7 @@ option('harfbuzz', + ' if available, many glyphs not directly addressable' + ' by a font\'s character map will be hinted also') -option('harfbuzz-calling-convention', +option('harfbuzz_calling_convention', type: 'combo', choices: ['auto', 'stdcall', 'cdecl'], value: 'auto',