[API] Add hb_buffer_[sg]et_not_found_glyph() and --not-found-glyph

Instead of using gid=0 when a character is not found in the font,
client can now set a custom value.  This is useful for shaper-driven
font fallback and to differentiate that from .notdef glyph.

Fixes https://github.com/harfbuzz/harfbuzz/issues/1360
This commit is contained in:
Behdad Esfahbod 2021-10-26 08:02:29 -06:00
parent 6ea6c581ed
commit da500568de
8 changed files with 65 additions and 6 deletions

View File

@ -85,6 +85,8 @@ hb_buffer_get_glyph_positions
hb_buffer_has_positions
hb_buffer_get_invisible_glyph
hb_buffer_set_invisible_glyph
hb_buffer_get_not_found_glyph
hb_buffer_set_not_found_glyph
hb_buffer_set_replacement_codepoint
hb_buffer_get_replacement_codepoint
hb_buffer_normalize_glyphs

View File

@ -224,6 +224,7 @@ hb_buffer_t::reset ()
flags = HB_BUFFER_FLAG_DEFAULT;
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
invisible = 0;
not_found = 0;
clear ();
}
@ -608,6 +609,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
0, /* invisible */
0, /* not_found */
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
HB_BUFFER_MAX_LEN_DEFAULT,
HB_BUFFER_MAX_OPS_DEFAULT,
@ -1158,6 +1160,46 @@ hb_buffer_get_invisible_glyph (hb_buffer_t *buffer)
return buffer->invisible;
}
/**
* hb_buffer_set_not_found_glyph:
* @buffer: An #hb_buffer_t
* @not_found: the not-found #hb_codepoint_t
*
* Sets the #hb_codepoint_t that replaces characters not found in
* the font during shaping.
*
* The not-found glyph defaults to zero, sometimes knows as the
* ".notdef" glyph. This API allows for differentiating the two.
*
* Since: REPLACEME
**/
void
hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
hb_codepoint_t not_found)
{
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->not_found = not_found;
}
/**
* hb_buffer_get_not_found_glyph:
* @buffer: An #hb_buffer_t
*
* See hb_buffer_set_not_found_glyph().
*
* Return value:
* The @buffer not-found #hb_codepoint_t
*
* Since: REPLACEME
**/
hb_codepoint_t
hb_buffer_get_not_found_glyph (hb_buffer_t *buffer)
{
return buffer->not_found;
}
/**
* hb_buffer_reset:

View File

@ -383,6 +383,13 @@ hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
HB_EXTERN hb_codepoint_t
hb_buffer_get_invisible_glyph (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
hb_codepoint_t not_found);
HB_EXTERN hb_codepoint_t
hb_buffer_get_not_found_glyph (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_reset (hb_buffer_t *buffer);

View File

@ -93,6 +93,7 @@ struct hb_buffer_t
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
hb_codepoint_t invisible; /* 0 or something else. */
hb_codepoint_t not_found; /* 0 or something else. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */

View File

@ -217,9 +217,10 @@ struct hb_font_t
}
hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
hb_codepoint_t *glyph)
hb_codepoint_t *glyph,
hb_codepoint_t not_found = 0)
{
*glyph = 0;
*glyph = not_found;
return klass->get.f.nominal_glyph (this, user_data,
unicode, glyph,
klass->user_data.nominal_glyph);
@ -238,9 +239,10 @@ struct hb_font_t
}
hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
hb_codepoint_t *glyph,
hb_codepoint_t not_found = 0)
{
*glyph = 0;
*glyph = not_found;
return klass->get.f.variation_glyph (this, user_data,
unicode, variation_selector, glyph,
klass->user_data.variation_glyph);

View File

@ -171,7 +171,7 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
hb_codepoint_t u = buffer->cur().codepoint;
hb_codepoint_t glyph = 0;
if (shortest && c->font->get_nominal_glyph (u, &glyph))
if (shortest && c->font->get_nominal_glyph (u, &glyph, c->not_found))
{
next_char (buffer, glyph);
return;
@ -183,7 +183,7 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
return;
}
if (!shortest && c->font->get_nominal_glyph (u, &glyph))
if (!shortest && c->font->get_nominal_glyph (u, &glyph, c->not_found))
{
next_char (buffer, glyph);
return;
@ -312,6 +312,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
buffer,
font,
buffer->unicode,
buffer->not_found,
plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
plan->shaper->compose ? plan->shaper->compose : compose_unicode
};

View File

@ -56,6 +56,7 @@ struct hb_ot_shape_normalize_context_t
hb_buffer_t *buffer;
hb_font_t *font;
hb_unicode_funcs_t *unicode;
const hb_codepoint_t not_found;
bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,

View File

@ -55,6 +55,7 @@ struct shape_options_t
(remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) |
0));
hb_buffer_set_invisible_glyph (buffer, invisible_glyph);
hb_buffer_set_not_found_glyph (buffer, not_found_glyph);
hb_buffer_set_cluster_level (buffer, cluster_level);
hb_buffer_guess_segment_properties (buffer);
}
@ -305,6 +306,7 @@ struct shape_options_t
char **shapers = nullptr;
hb_bool_t utf8_clusters = false;
hb_codepoint_t invisible_glyph = 0;
hb_codepoint_t not_found_glyph = 0;
hb_buffer_cluster_level_t cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
hb_bool_t normalize_glyphs = false;
hb_bool_t verify = false;
@ -427,6 +429,7 @@ shape_options_t::add_options (option_parser_t *parser)
{"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->preserve_default_ignorables, "Preserve Default-Ignorable characters", nullptr},
{"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->remove_default_ignorables, "Remove Default-Ignorable characters", nullptr},
{"invisible-glyph", 0, 0, G_OPTION_ARG_INT, &this->invisible_glyph, "Glyph value to replace Default-Ignorables with", nullptr},
{"not-found-glyph", 0, 0, G_OPTION_ARG_INT, &this->not_found_glyph, "Glyph value to replace not-found characters with", nullptr},
{"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", nullptr},
{"cluster-level", 0, 0, G_OPTION_ARG_INT, &this->cluster_level, "Cluster merging level (default: 0)", "0/1/2"},
{"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", nullptr},