Merge pull request #5122 from harfbuzz/using

Add API for querying font-funcs / face-loaders and setting them using strings
This commit is contained in:
Behdad Esfahbod 2025-03-09 05:28:09 -06:00 committed by GitHub
commit 0a01fc558b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 458 additions and 292 deletions

View file

@ -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
@ -458,6 +460,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

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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"

View file

@ -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'),
@ -55,13 +56,11 @@ 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',
'--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()
@ -69,20 +68,20 @@ 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 + [
'--lib', '-p', 'harfbuzz_fontations',
'--target-dir', meson.current_build_dir(),
'--manifest-path', meson.current_source_dir() / 'Cargo.toml',
'--', '-D', 'warnings',
],
timeout: 120,
)
endif
rustfmt_fix = run_target(
'rustfmt-fix',
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs],
command: [
rustfmt,
'--edition', '2021',
@ -95,6 +94,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',

View file

@ -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_); }

View file

@ -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
@ -318,7 +325,135 @@ hb_face_create_from_file_or_fail (const char *file_name,
return face;
}
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` 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,
* 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.
*
* XSince: REPLACEME
**/
hb_face_t *
hb_face_create_from_file_or_fail_using (const char *file_name,
unsigned int index,
const char *loader_name)
{
bool retry = false;
if (!loader_name || !*loader_name)
{
static hb_atomic_ptr_t<const char> static_funcs_name;
loader_name = static_funcs_name.get_acquire ();
if (!loader_name)
{
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 (loader_name && !*loader_name) loader_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))
return supported_face_loaders[i].func (file_name, index);
}
if (retry)
{
retry = false;
loader_name = nullptr;
goto retry;
}
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<const char *,
hb_face_loader_list_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 ();
}
#endif
/**
* hb_face_get_empty:

View file

@ -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

View file

@ -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
@ -1854,10 +1867,7 @@ 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
hb_font_set_funcs_using (font, nullptr);
#ifndef HB_NO_VAR
if (face && face->index >> 16)
@ -2292,6 +2302,133 @@ 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[] =
{
#ifndef HB_NO_OT_FONT
{"ot", hb_ot_font_set_funcs},
#endif
#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, or `NULL`
*
* Sets the font-functions structure to use for a font, based on the
* specified name.
*
* 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.
*
* 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)
{
bool retry = false;
if (!name || !*name)
{
static hb_atomic_ptr_t<const char> 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)
{
supported_font_funcs[i].func (font);
if (name || font->klass != hb_font_funcs_get_empty ())
return true;
}
if (retry)
{
retry = false;
name = nullptr;
goto retry;
}
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<const char *,
hb_font_funcs_list_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): a
* `NULL`-terminated array of supported font functions
* constant strings. The returned array is owned by HarfBuzz
* and should not be modified or freed.
*
* XSince: REPLACEME
**/
const char **
hb_font_list_funcs ()
{
return static_font_funcs_list.get_unconst ();
}
/**
* hb_font_set_scale:
@ -2607,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)
{
@ -2677,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()
@ -2749,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;
@ -2787,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);
@ -2834,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;

View file

@ -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,

View file

@ -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;

View file

@ -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;
@ -213,9 +213,10 @@ _hb_ft_hb_font_check_changed (hb_font_t *font,
{
if (font->serial != ft_font->cached_serial)
{
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;
@ -478,6 +479,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 +564,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 +619,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 +665,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 +686,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 +760,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 +839,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 +931,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 +1007,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 +1475,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

View file

@ -91,8 +91,10 @@ 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
* modified or freed.
*
* Since: 0.9.2
**/

View file

@ -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,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);
set_font_funcs (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;
@ -1124,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);
set_font_funcs (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;
@ -1165,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';
set_font_funcs (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';

View file

@ -93,8 +93,11 @@ thread_func (void *data)
}
static void
test_body (void)
test_body (const char *backend)
{
bool ret = hb_font_set_funcs_using (font, backend);
g_assert (ret);
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,8 @@ 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 ();
for (const char **font_funcs = hb_font_list_funcs (); *font_funcs; font_funcs++)
test_body (*font_funcs);
hb_buffer_destroy (ref_buffer);

View file

@ -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;

View file

@ -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);

View file

@ -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};

View file

@ -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;

View file

@ -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();

View file

@ -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<std::thread> threads;
for (unsigned i = 0; i < num_threads; i++)
@ -200,10 +183,8 @@ 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
for (const char **font_funcs = hb_font_list_funcs (); *font_funcs; font_funcs++)
test_backend (*font_funcs, is_var, test_input);
}
}

View file

@ -29,13 +29,6 @@
#include "options.hh"
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#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,

View file

@ -29,16 +29,9 @@
#include "face-options.hh"
#include <hb-ot.h>
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#ifdef HAVE_FONTATIONS
#include <hb-fontations.h>
#endif
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#endif
#define FONT_SIZE_UPEM 0x7FFFFFFF
#define FONT_SIZE_NONE 0
@ -84,24 +77,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 +105,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
@ -176,6 +147,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,
@ -309,16 +292,20 @@ 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++)
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].name);
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);
@ -349,6 +336,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"},