[autofit] Some preparations for loading HarfBuzz dynamically. (1/4)

* src/autofit/ft-hb.h: New file, defining the `hb` macro.  Later on, we
  provide a different definition of this macro depending on a yet-to-come
  configuration option to support dynamic loading of HarfBuzz functions.

* src/autofit/afadjust.c, src/autofit/afglobal.c, src/autofit/afshaper.c,
  stc/ft-hb-ft.c: Use it.
This commit is contained in:
Behdad Esfahbod (بهداد اسفهبد)
2025-04-26 12:22:23 +02:00
committed by Werner Lemberg
parent 3eb4eadea5
commit 8b443d70fe
6 changed files with 153 additions and 115 deletions

View File

@@ -1045,7 +1045,7 @@
/* Iterate over all lookups. */
while ( hb_set_next( gsub_lookups, &lookup_index ) )
while ( hb( set_next )( gsub_lookups, &lookup_index ) )
{
FT_Bool lookup_done = FALSE;
unsigned int start_offset = 0;
@@ -1059,19 +1059,19 @@
unsigned int n;
(void)hb_ot_layout_lookup_get_glyph_alternates( hb_face,
lookup_index,
glyph,
start_offset,
&alternates_count,
alternates );
(void)hb( ot_layout_lookup_get_glyph_alternates )( hb_face,
lookup_index,
glyph,
start_offset,
&alternates_count,
alternates );
start_offset += ALTERNATE_CHUNK;
if ( alternates_count < ALTERNATE_CHUNK )
lookup_done = TRUE;
for ( n = 0; n < alternates_count; n++ )
hb_set_add( result, alternates[n] );
hb( set_add )( result, alternates[n] );
}
}
}
@@ -1085,38 +1085,38 @@
hb_set_t *gsub_lookups,
hb_set_t *result )
{
hb_face_t *hb_face = hb_font_get_face( hb_font );
hb_set_t *helper_result = hb_set_create();
hb_face_t *hb_face = hb( font_get_face )( hb_font );
hb_set_t *helper_result = hb( set_create )();
/* Seed `helper_result` with `glyph` itself, then get all possible */
/* values. Note that we can't use `hb_set_next` to control the */
/* loop because we modify `helper_result` during iteration. */
hb_set_add( helper_result, glyph );
while ( !hb_set_is_empty( helper_result ) )
hb( set_add )( helper_result, glyph );
while ( !hb( set_is_empty )( helper_result ) )
{
hb_codepoint_t elem;
/* Always get the smallest element of the set. */
elem = HB_SET_VALUE_INVALID;
hb_set_next( helper_result, &elem );
hb( set_next )( helper_result, &elem );
/* Don't process already handled glyphs again. */
if ( !hb_set_has( result, elem ) )
if ( !hb( set_has )( result, elem ) )
{
/* This call updates the glyph set in `helper_result`. */
af_get_glyph_alternates_helper( hb_face,
elem,
gsub_lookups,
helper_result );
hb_set_add( result, elem );
hb( set_add )( result, elem );
}
hb_set_del( helper_result, elem );
hb( set_del )( helper_result, elem );
}
hb_set_destroy( helper_result );
hb( set_destroy )( helper_result );
}
# endif /* HB_VERSION_ATLEAST */
@@ -1169,10 +1169,10 @@
/* 'empty' objects that do nothing. */
hb_font_t *hb_font = globals->hb_font;
hb_face_t *hb_face = hb_font_get_face( hb_font );
hb_face_t *hb_face = hb( font_get_face )( hb_font );
hb_set_t *result_set = hb_set_create();
hb_set_t *gsub_lookups = hb_set_create();
hb_set_t *result_set = hb( set_create )();
hb_set_t *gsub_lookups = hb( set_create )();
FT_UInt32 codepoint;
FT_UInt glyph_index;
@@ -1183,10 +1183,10 @@
/* Compute set of all GSUB lookups. */
hb_ot_layout_collect_lookups( hb_face,
HB_OT_TAG_GSUB,
NULL, NULL, NULL,
gsub_lookups );
hb( ot_layout_collect_lookups )( hb_face,
HB_OT_TAG_GSUB,
NULL, NULL, NULL,
gsub_lookups );
/* Find all glyph alternates of the code points in */
/* the adjustment database and put them into `map`. */
@@ -1206,7 +1206,7 @@
result_set );
glyph = HB_SET_VALUE_INVALID;
while ( hb_set_next( result_set, &glyph ) )
while ( hb( set_next )( result_set, &glyph ) )
{
FT_Long insert_point;
@@ -1222,11 +1222,11 @@
( *map )->entries[insert_point].codepoint = codepoint;
}
hb_set_clear( result_set );
hb( set_clear )( result_set );
}
hb_set_destroy( result_set );
hb_set_destroy( gsub_lookups );
hb( set_destroy )( result_set );
hb( set_destroy )( gsub_lookups );
ft_qsort( ( *map )->entries,
( *map )->length,

View File

@@ -357,7 +357,7 @@
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
globals->hb_font = ft_hb_ft_font_create( face, NULL );
globals->hb_buf = hb_buffer_create();
globals->hb_buf = hb( buffer_create )();
#endif
error = af_face_globals_compute_style_coverage( globals );
@@ -405,8 +405,8 @@
}
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
hb_font_destroy( globals->hb_font );
hb_buffer_destroy( globals->hb_buf );
hb( font_destroy )( globals->hb_font );
hb( buffer_destroy )( globals->hb_buf );
#endif
/* no need to free `globals->glyph_styles'; */

View File

@@ -124,7 +124,7 @@
if ( !globals || !style_class || !gstyles )
return FT_THROW( Invalid_Argument );
face = hb_font_get_face( globals->hb_font );
face = hb( font_get_face )( globals->hb_font );
coverage_tags = coverages[style_class->coverage];
script = scripts[style_class->script];
@@ -137,12 +137,12 @@
hb_tag_t tags[3];
hb_ot_tags_from_script_and_language( script,
HB_LANGUAGE_INVALID,
&tags_count,
tags,
NULL,
NULL );
hb( ot_tags_from_script_and_language )( script,
HB_LANGUAGE_INVALID,
&tags_count,
tags,
NULL,
NULL );
script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE;
script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE;
script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE;
@@ -170,15 +170,15 @@
goto Exit;
}
gsub_lookups = hb_set_create();
hb_ot_layout_collect_lookups( face,
HB_OT_TAG_GSUB,
script_tags,
NULL,
coverage_tags,
gsub_lookups );
gsub_lookups = hb( set_create )();
hb( ot_layout_collect_lookups )( face,
HB_OT_TAG_GSUB,
script_tags,
NULL,
coverage_tags,
gsub_lookups );
if ( hb_set_is_empty( gsub_lookups ) )
if ( hb( set_is_empty )( gsub_lookups ) )
goto Exit; /* nothing to do */
FT_TRACE4(( "GSUB lookups (style `%s'):\n",
@@ -189,8 +189,8 @@
count = 0;
#endif
gsub_glyphs = hb_set_create();
for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, &idx ); )
gsub_glyphs = hb( set_create )();
for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups, &idx ); )
{
#ifdef FT_DEBUG_LEVEL_TRACE
FT_TRACE4(( " %d", idx ));
@@ -198,12 +198,12 @@
#endif
/* get output coverage of GSUB feature */
hb_ot_layout_lookup_collect_glyphs( face,
HB_OT_TAG_GSUB,
idx,
NULL,
NULL,
NULL,
hb( ot_layout_lookup_collect_glyphs )( face,
HB_OT_TAG_GSUB,
idx,
NULL,
NULL,
NULL,
gsub_glyphs );
}
@@ -218,20 +218,20 @@
af_style_names[style_class->style] ));
FT_TRACE4(( " " ));
gpos_lookups = hb_set_create();
hb_ot_layout_collect_lookups( face,
HB_OT_TAG_GPOS,
script_tags,
NULL,
coverage_tags,
gpos_lookups );
gpos_lookups = hb( set_create )();
hb( ot_layout_collect_lookups )( face,
HB_OT_TAG_GPOS,
script_tags,
NULL,
coverage_tags,
gpos_lookups );
#ifdef FT_DEBUG_LEVEL_TRACE
count = 0;
#endif
gpos_glyphs = hb_set_create();
for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gpos_lookups, &idx ); )
gpos_glyphs = hb( set_create )();
for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gpos_lookups, &idx ); )
{
#ifdef FT_DEBUG_LEVEL_TRACE
FT_TRACE4(( " %d", idx ));
@@ -239,13 +239,13 @@
#endif
/* get input coverage of GPOS feature */
hb_ot_layout_lookup_collect_glyphs( face,
HB_OT_TAG_GPOS,
idx,
NULL,
gpos_glyphs,
NULL,
NULL );
hb( ot_layout_lookup_collect_glyphs )( face,
HB_OT_TAG_GPOS,
idx,
NULL,
gpos_glyphs,
NULL,
NULL );
}
#ifdef FT_DEBUG_LEVEL_TRACE
@@ -281,14 +281,14 @@
GET_UTF8_CHAR( ch, p );
for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups,
&idx ); )
for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups,
&idx ); )
{
hb_codepoint_t gidx = FT_Get_Char_Index( globals->face, ch );
if ( hb_ot_layout_lookup_would_substitute( face, idx,
&gidx, 1, 1 ) )
if ( hb( ot_layout_lookup_would_substitute )( face, idx,
&gidx, 1, 1 ) )
{
found = 1;
break;
@@ -352,14 +352,14 @@
*
*/
if ( style_class->coverage != AF_COVERAGE_DEFAULT )
hb_set_subtract( gsub_glyphs, gpos_glyphs );
hb( set_subtract )( gsub_glyphs, gpos_glyphs );
#ifdef FT_DEBUG_LEVEL_TRACE
FT_TRACE4(( " glyphs without GPOS data (`*' means already assigned)" ));
count = 0;
#endif
for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_glyphs, &idx ); )
for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_glyphs, &idx ); )
{
#ifdef FT_DEBUG_LEVEL_TRACE
if ( !( count % 10 ) )
@@ -397,10 +397,10 @@
#endif
Exit:
hb_set_destroy( gsub_lookups );
hb_set_destroy( gsub_glyphs );
hb_set_destroy( gpos_lookups );
hb_set_destroy( gpos_glyphs );
hb( set_destroy )( gsub_lookups );
hb( set_destroy )( gsub_glyphs );
hb( set_destroy )( gpos_lookups );
hb( set_destroy )( gpos_glyphs );
return FT_Err_Ok;
}
@@ -442,7 +442,7 @@
{
FT_UNUSED( face );
return (void*)hb_buffer_create();
return (void*)hb( buffer_create )();
}
@@ -452,7 +452,7 @@
{
FT_UNUSED( face );
hb_buffer_destroy( (hb_buffer_t*)buf );
hb( buffer_destroy )( (hb_buffer_t*)buf );
}
@@ -480,7 +480,7 @@
font = metrics->globals->hb_font;
/* we shape at a size of units per EM; this means font units */
hb_font_set_scale( font, upem, upem );
hb( font_set_scale )( font, upem, upem );
while ( *p == ' ' )
p++;
@@ -492,15 +492,15 @@
len = (int)( q - p );
/* feed character(s) to the HarfBuzz buffer */
hb_buffer_clear_contents( buf );
hb_buffer_add_utf8( buf, p, len, 0, len );
hb( buffer_clear_contents )( buf );
hb( buffer_add_utf8 )( buf, p, len, 0, len );
/* we let HarfBuzz guess the script and writing direction */
hb_buffer_guess_segment_properties( buf );
hb( buffer_guess_segment_properties )( buf );
/* shape buffer, which means conversion from character codes to */
/* glyph indices, possibly applying a feature */
hb_shape( font, buf, feature, feature ? 1 : 0 );
hb( shape )( font, buf, feature, feature ? 1 : 0 );
if ( feature )
{
@@ -517,13 +517,13 @@
/* glyph indices; otherwise the affected glyph or glyphs aren't */
/* available at all in the feature */
hb_buffer_clear_contents( hb_buf );
hb_buffer_add_utf8( hb_buf, p, len, 0, len );
hb_buffer_guess_segment_properties( hb_buf );
hb_shape( font, hb_buf, NULL, 0 );
hb( buffer_clear_contents )( hb_buf );
hb( buffer_add_utf8 )( hb_buf, p, len, 0, len );
hb( buffer_guess_segment_properties )( hb_buf );
hb( shape )( font, hb_buf, NULL, 0 );
ginfo = hb_buffer_get_glyph_infos( buf, &gcount );
hb_ginfo = hb_buffer_get_glyph_infos( hb_buf, &hb_gcount );
ginfo = hb( buffer_get_glyph_infos )( buf, &gcount );
hb_ginfo = hb( buffer_get_glyph_infos )( hb_buf, &hb_gcount );
if ( gcount == hb_gcount )
{
@@ -537,12 +537,12 @@
if ( i == gcount )
{
/* both buffers have identical glyph indices */
hb_buffer_clear_contents( buf );
hb( buffer_clear_contents )( buf );
}
}
}
*count = hb_buffer_get_length( buf );
*count = hb( buffer_get_length )( buf );
#ifdef FT_DEBUG_LEVEL_TRACE
if ( feature && *count > 1 )
@@ -569,8 +569,8 @@
FT_UNUSED( metrics );
ginfo = hb_buffer_get_glyph_infos( buf, &gcount );
gpos = hb_buffer_get_glyph_positions( buf, &gcount );
ginfo = hb( buffer_get_glyph_infos )( buf, &gcount );
gpos = hb( buffer_get_glyph_positions )( buf, &gcount );
if ( idx >= gcount )
return 0;

View File

@@ -62,9 +62,9 @@ ft_hb_ft_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
return NULL;
}
return hb_blob_create ((const char *) buffer, length,
HB_MEMORY_MODE_WRITABLE,
buffer, ft_sfree);
return hb(blob_create) ((const char *) buffer, length,
HB_MEMORY_MODE_WRITABLE,
buffer, ft_sfree);
}
static hb_face_t *
@@ -76,18 +76,18 @@ ft_hb_ft_face_create (FT_Face ft_face,
if (!ft_face->stream->read) {
hb_blob_t *blob;
blob = hb_blob_create ((const char *) ft_face->stream->base,
(unsigned int) ft_face->stream->size,
HB_MEMORY_MODE_READONLY,
ft_face, destroy);
face = hb_face_create (blob, ft_face->face_index);
hb_blob_destroy (blob);
blob = hb(blob_create) ((const char *) ft_face->stream->base,
(unsigned int) ft_face->stream->size,
HB_MEMORY_MODE_READONLY,
ft_face, destroy);
face = hb(face_create) (blob, ft_face->face_index);
hb(blob_destroy) (blob);
} else {
face = hb_face_create_for_tables (ft_hb_ft_reference_table, ft_face, destroy);
face = hb(face_create_for_tables) (ft_hb_ft_reference_table, ft_face, destroy);
}
hb_face_set_index (face, ft_face->face_index);
hb_face_set_upem (face, ft_face->units_per_EM);
hb(face_set_index) (face, ft_face->face_index);
hb(face_set_upem) (face, ft_face->units_per_EM);
return face;
}
@@ -100,8 +100,8 @@ ft_hb_ft_font_create (FT_Face ft_face,
hb_face_t *face;
face = ft_hb_ft_face_create (ft_face, destroy);
font = hb_font_create (face);
hb_face_destroy (face);
font = hb(font_create) (face);
hb(face_destroy) (face);
return font;
}

View File

@@ -27,10 +27,7 @@
#ifndef FT_HB_FT_H
#define FT_HB_FT_H
#include <hb.h>
#include <freetype/internal/compiler-macros.h>
#include <freetype/freetype.h>
#include "ft-hb.h"
FT_BEGIN_HEADER

41
src/autofit/ft-hb.h Normal file
View File

@@ -0,0 +1,41 @@
/****************************************************************************
*
* ft-hb.h
*
* FreeType-HarfBuzz bridge (specification).
*
* 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.
*
*/
#ifndef FT_HB_H
#define FT_HB_H
#include <hb.h>
#include <freetype/internal/compiler-macros.h>
#include <freetype/freetype.h>
FT_BEGIN_HEADER
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
#define hb( x ) hb_ ## x
#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */
FT_END_HEADER
#endif /* FT_HB_H */
/* END */