From 7651fe00befc98c7b1ffb364abdc212282704f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Behdad=20Esfahbod=20=28=D8=A8=D9=87=D8=AF=D8=A7=D8=AF=20?= =?UTF-8?q?=D8=A7=D8=B3=D9=81=D9=87=D8=A8=D8=AF=29?= Date: Sun, 27 Apr 2025 18:44:49 +0200 Subject: [PATCH] [autofit] Enable dynamic loading of HarfBuzz. (1/2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit activates the mini-HarfBuzz header files and provides the necessary infrastructure for dynamically loading HarfBuzz if `FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC` is defined (this macro gets set up in a follow-up commit). * src/autofit/ft-hb.c: New file, providing `ft_hb_funcs_init` and `ft_hb_funcs_done` for loading HarfBuzz dynamically. The name of the library is hold in the macro `FT_LIBHARFBUZZ`, which can be overridden. * src/autofit/ft-hb.h: Don't include `hb.h` but `ft-hb-types.h`. (hb): Modified to handle both standard linking and dynamically loading of HarfBuzz. (HB_EXTERN): New macro to load `ft-hb-decls.h`. * src/autofit/afadjust.c [FT_CONFIG_OPTION_USE_HARFBUZZ]: For the sake of dynamically loading the HarfBuzz library, replace the compile-time macro `HB_VERSION_ATLEAST` with a call to the run-time function `hb_version_atleast` where necessary – a follow-up commit will set the minimum version of HarfBuzz to 2.6.8, which provides all necessary functions needed by FreeType. * src/autofit/afmodule.h: Include `ft-hb.h`. (AF_ModuleRec) [FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC]: Add `hb_funcs` structure to hold pointers to the dynamically loaded HarfBuzz functions. * src/autofit/afmodule.c (af_autofitter_init, af_autofitter_done) [FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC]: Call `ft_hb_funcs_init` and `ft_hb_funcs_done`. * src/autofit/afshaper.h: Updated. * src/autofit/autofit.c: Include `ft-hb.c`. * src/autofit/rules.mk (AUTOF_DRV_SRC, AUTOF_DRV_H): Updated. --- src/autofit/afadjust.c | 11 +-- src/autofit/afmodule.c | 10 +++ src/autofit/afmodule.h | 6 ++ src/autofit/afshaper.h | 9 --- src/autofit/autofit.c | 1 + src/autofit/ft-hb.c | 165 +++++++++++++++++++++++++++++++++++++++++ src/autofit/ft-hb.h | 41 +++++++++- src/autofit/rules.mk | 18 +++-- 8 files changed, 233 insertions(+), 28 deletions(-) create mode 100644 src/autofit/ft-hb.c diff --git a/src/autofit/afadjust.c b/src/autofit/afadjust.c index 6e9f5f7f8..9e1b80761 100644 --- a/src/autofit/afadjust.c +++ b/src/autofit/afadjust.c @@ -987,7 +987,6 @@ #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ -# if HB_VERSION_ATLEAST( 7, 2, 0 ) /* Find all glyphs that a code point could turn into from the OpenType @@ -1124,7 +1123,6 @@ hb( set_destroy )( helper_result ); } -# endif /* HB_VERSION_ATLEAST */ #endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ @@ -1166,8 +1164,8 @@ goto Exit; #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ -# if HB_VERSION_ATLEAST( 7, 2, 0 ) + if ( hb( version_atleast )( 7, 2, 0 ) ) { /* No need to check whether HarfBuzz has allocation issues; */ /* it continues to work in such cases and simply returns */ @@ -1277,10 +1275,9 @@ codepoint = FT_Get_Next_Char( face, codepoint, &glyph_index ); } } + else -# endif /* HB_VERSION_ATLEAST */ - -#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ { FT_UInt i; @@ -1313,8 +1310,6 @@ af_reverse_character_map_entry_compare ); } -#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ - FT_TRACE4(( " reverse character map built successfully" " with %ld entries\n", ( *map )->length )); diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c index 726f6ca2b..9c1f2c211 100644 --- a/src/autofit/afmodule.c +++ b/src/autofit/afmodule.c @@ -412,6 +412,11 @@ module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + ft_hb_funcs_init( module ); +#endif + return FT_Err_Ok; } @@ -421,6 +426,11 @@ { FT_UNUSED( ft_module ); +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + ft_hb_funcs_done( (AF_Module)ft_module ); +#endif + #ifdef FT_DEBUG_AUTOFIT if ( af_debug_hints_rec_->memory ) af_glyph_hints_done( af_debug_hints_rec_ ); diff --git a/src/autofit/afmodule.h b/src/autofit/afmodule.h index 91a1abfef..f5a406c76 100644 --- a/src/autofit/afmodule.h +++ b/src/autofit/afmodule.h @@ -22,6 +22,7 @@ #include #include +#include "ft-hb.h" FT_BEGIN_HEADER @@ -40,6 +41,11 @@ 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 ) + ft_hb_funcs_t* hb_funcs; +#endif + } AF_ModuleRec, *AF_Module; diff --git a/src/autofit/afshaper.h b/src/autofit/afshaper.h index f72995319..4a4176f89 100644 --- a/src/autofit/afshaper.h +++ b/src/autofit/afshaper.h @@ -23,15 +23,6 @@ #include -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - -#include -#include -#include "ft-hb-ft.h" - -#endif - - FT_BEGIN_HEADER FT_Error diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c index a283e694d..e7da68cf5 100644 --- a/src/autofit/autofit.c +++ b/src/autofit/autofit.c @@ -18,6 +18,7 @@ #define FT_MAKE_OPTION_SINGLE_OBJECT +#include "ft-hb.c" #include "ft-hb-ft.c" #include "afadjust.c" #include "afblue.c" diff --git a/src/autofit/ft-hb.c b/src/autofit/ft-hb.c new file mode 100644 index 000000000..110d7bf60 --- /dev/null +++ b/src/autofit/ft-hb.c @@ -0,0 +1,165 @@ +/**************************************************************************** + * + * ft-hb.c + * + * FreeType-HarfBuzz bridge (body). + * + * Copyright (C) 2025 by + * Behdad Esfahbod. + * + * 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. + * + */ + + +#include +#include + +#include "afglobal.h" + +#include "ft-hb.h" + + +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + +#ifndef FT_LIBHARFBUZZ +# ifdef _WIN32 +# define FT_LIBHARFBUZZ "libharfbuzz-0.dll" +# else +# ifdef __APPLE__ +# define FT_LIBHARFBUZZ "libharfbuzz.0.dylib" +# else +# define FT_LIBHARFBUZZ "libharfbuzz.so.0" +# endif +# endif +#endif + +#ifdef _WIN32 + +# include + +#else /* !_WIN32 */ + +# include + + /* The GCC pragma suppresses the warning "ISO C forbids */ + /* assignment between function pointer and 'void *'", which */ + /* inevitably gets emitted with `-Wpedantic`; see the man */ + /* page of function `dlsym` for more information. */ +# if defined( __GNUC__ ) +# pragma GCC diagnostic push +# ifndef __cplusplus +# pragma GCC diagnostic ignored "-Wpedantic" +# endif +# endif + +#endif /* !_WIN32 */ + + + FT_LOCAL_DEF( void ) + ft_hb_funcs_init( struct AF_ModuleRec_ *af_module ) + { + FT_Memory memory = af_module->root.memory; + FT_Error error; + + ft_hb_funcs_t *funcs = NULL; + ft_hb_version_atleast_func_t version_atleast = NULL; + +#ifdef _WIN32 + HANDLE lib; +# define DLSYM( lib, name ) \ + (ft_ ## name ## _func_t)GetProcAddress( lib, #name ) +#else + void *lib; +# define DLSYM( lib, name ) \ + (ft_ ## name ## _func_t)dlsym( lib, #name ) +#endif + + + af_module->hb_funcs = NULL; + + if ( FT_NEW( funcs ) ) + return; + FT_ZERO( funcs ); + +#ifdef _WIN32 + + lib = LoadLibraryA( FT_LIBHARFBUZZ ); + if ( !lib ) + goto Fail; + version_atleast = DLSYM( lib, hb_version_atleast ); + +#else /* !_WIN32 */ + + lib = RTLD_DEFAULT; + version_atleast = DLSYM( lib, hb_version_atleast ); + if ( !version_atleast ) + { + /* Load the HarfBuzz library. + * + * We never close the library, since we opened it with RTLD_GLOBAL. + * This is important for the case where we are using HarfBuzz as a + * shared library, and we want to use the symbols from the library in + * other shared libraries or clients. HarfBuzz holds onto global + * variables, and closing the library will cause them to be + * invalidated. + */ + lib = dlopen( FT_LIBHARFBUZZ, RTLD_LAZY | RTLD_GLOBAL ); + if ( !lib ) + goto Fail; + version_atleast = DLSYM( lib, hb_version_atleast ); + if ( !version_atleast ) + goto Fail; + } + +#endif /* !_WIN32 */ + + /* Load all symbols we use. */ +#define HB_EXTERN( ret, name, args ) \ + { \ + funcs->name = DLSYM( lib, name ); \ + if ( !funcs->name ) \ + goto Fail; \ + } +#include "ft-hb-decls.h" +#undef HB_EXTERN + +#undef DLSYM + + af_module->hb_funcs = funcs; + return; + + Fail: + if ( funcs ) + FT_FREE( funcs ); + } + + + FT_LOCAL_DEF( void ) + ft_hb_funcs_done( struct AF_ModuleRec_ *af_module ) + { + FT_Memory memory = af_module->root.memory; + + + if ( af_module->hb_funcs ) + { + FT_FREE( af_module->hb_funcs ); + af_module->hb_funcs = NULL; + } + } + +#ifndef _WIN32 +# if defined( __GNUC__ ) +# pragma GCC diagnostic pop +# endif +#endif + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + + +/* END */ diff --git a/src/autofit/ft-hb.h b/src/autofit/ft-hb.h index 05e8df5e3..399bfa96a 100644 --- a/src/autofit/ft-hb.h +++ b/src/autofit/ft-hb.h @@ -19,8 +19,6 @@ #ifndef FT_HB_H #define FT_HB_H -#include - #include #include @@ -29,10 +27,47 @@ FT_BEGIN_HEADER #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ -#define hb( x ) hb_ ## x +# include "ft-hb-types.h" + +# ifdef FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC + +# 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; + + struct AF_ModuleRec_; + + FT_LOCAL( void ) + ft_hb_funcs_init( struct AF_ModuleRec_ *af_module ); + + FT_LOCAL( void ) + ft_hb_funcs_done( struct AF_ModuleRec_ *af_module ); + +# define hb( x ) globals->module->hb_funcs->hb_ ## x + +# else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + +# define HB_EXTERN( ret, name, args ) \ + ret name args; +# include "ft-hb-decls.h" +# undef HB_EXTERN + +# define hb( x ) hb_ ## x + +# endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ #endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + FT_END_HEADER #endif /* FT_HB_H */ diff --git a/src/autofit/rules.mk b/src/autofit/rules.mk index b8766d399..c10288f1c 100644 --- a/src/autofit/rules.mk +++ b/src/autofit/rules.mk @@ -40,18 +40,20 @@ AUTOF_DRV_SRC := $(AUTOF_DIR)/afadjust.c \ $(AUTOF_DIR)/afmodule.c \ $(AUTOF_DIR)/afranges.c \ $(AUTOF_DIR)/afshaper.c \ + $(AUTOF_DIR)/ft-hb.c \ $(AUTOF_DIR)/ft-hb-ft.c # AUTOF driver headers # -AUTOF_DRV_H := $(AUTOF_DRV_SRC:%c=%h) \ - $(AUTOF_DIR)/afcover.h \ - $(AUTOF_DIR)/aferrors.h \ - $(AUTOF_DIR)/afscript.h \ - $(AUTOF_DIR)/afstyles.h \ - $(AUTOF_DIR)/aftypes.h \ - $(AUTOF_DIR)/afws-decl.h \ - $(AUTOF_DIR)/afws-iter.h +AUTOF_DRV_H := $(AUTOF_DRV_SRC:%c=%h) \ + $(AUTOF_DIR)/afcover.h \ + $(AUTOF_DIR)/aferrors.h \ + $(AUTOF_DIR)/afscript.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 driver object(s)