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;