[face] Two new APIs:

+ hb_face_create_from_file_or_fail_using()
+ hb_face_list_loaders()
This commit is contained in:
Behdad Esfahbod 2025-03-09 01:25:52 -07:00
parent 50ea460b93
commit 39ade99d47
5 changed files with 158 additions and 72 deletions

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

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

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,6 +29,10 @@
#include "face-options.hh"
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#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);