[indic-like] Add per-lookup per-syllable flag

This allows mix-and-matching per-syllable and other lookups.
In fact, removes the clear-syllables call completely.

Fixes https://github.com/harfbuzz/harfbuzz/issues/3513
This commit is contained in:
Behdad Esfahbod 2022-03-28 12:38:56 -06:00
parent 61486746d3
commit 044d7a06db
11 changed files with 61 additions and 66 deletions

View File

@ -408,9 +408,10 @@ struct hb_ot_apply_context_t :
{
matcher_t () :
lookup_props (0),
mask (-1),
ignore_zwnj (false),
ignore_zwj (false),
mask (-1),
per_syllable (false),
syllable {0},
match_func (nullptr),
match_data (nullptr) {}
@ -421,7 +422,8 @@ struct hb_ot_apply_context_t :
void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
void set_mask (hb_mask_t mask_) { mask = mask_; }
void set_syllable (uint8_t syllable_) { syllable = syllable_; }
void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; }
void set_syllable (uint8_t syllable_) { syllable = per_syllable ? syllable_ : 0; }
void set_match_func (match_func_t match_func_,
const void *match_data_)
{ match_func = match_func_; match_data = match_data_; }
@ -467,9 +469,10 @@ struct hb_ot_apply_context_t :
protected:
unsigned int lookup_props;
hb_mask_t mask;
bool ignore_zwnj;
bool ignore_zwj;
hb_mask_t mask;
bool per_syllable;
uint8_t syllable;
match_func_t match_func;
const void *match_data;
@ -488,6 +491,7 @@ struct hb_ot_apply_context_t :
/* Ignore ZWJ if we are matching context, or asked to. */
matcher.set_ignore_zwj (context_match || c->auto_zwj);
matcher.set_mask (context_match ? -1 : c->lookup_mask);
matcher.set_per_syllable (c->per_syllable);
}
void set_lookup_props (unsigned int lookup_props)
{
@ -634,6 +638,7 @@ struct hb_ot_apply_context_t :
bool has_glyph_classes;
bool auto_zwnj;
bool auto_zwj;
bool per_syllable;
bool random;
uint32_t random_state;
@ -662,6 +667,7 @@ struct hb_ot_apply_context_t :
has_glyph_classes (gdef.has_glyph_classes ()),
auto_zwnj (true),
auto_zwj (true),
per_syllable (false),
random (false),
random_state (1) { init_iters (); }
@ -674,6 +680,7 @@ struct hb_ot_apply_context_t :
void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); }
void set_random (bool random_) { random = random_; }
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }

View File

@ -1931,6 +1931,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
c.set_random (lookups[table_index][i].random);
c.set_per_syllable (lookups[table_index][i].per_syllable);
apply_string<Proxy> (&c,
proxy.table.get_lookup (lookup_index),

View File

@ -172,17 +172,6 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
return start;
}
static inline void
_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
info[i].syllable() = 0;
}
/* unicode_props */

View File

@ -117,7 +117,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
hb_mask_t mask,
bool auto_zwnj,
bool auto_zwj,
bool random)
bool random,
bool per_syllable)
{
unsigned int lookup_indices[32];
unsigned int offset, len;
@ -145,6 +146,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
lookup->auto_zwnj = auto_zwnj;
lookup->auto_zwj = auto_zwj;
lookup->random = random;
lookup->per_syllable = per_syllable;
}
offset += len;
@ -277,6 +279,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
map->random = !!(info->flags & F_RANDOM);
map->per_syllable = !!(info->flags & F_PER_SYLLABLE);
if ((info->flags & F_GLOBAL) && info->max_value == 1) {
/* Uses the global bit */
map->shift = global_bit_shift;
@ -319,7 +322,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
m.features[i].mask,
m.features[i].auto_zwnj,
m.features[i].auto_zwj,
m.features[i].random);
m.features[i].random,
m.features[i].per_syllable);
/* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].length)

View File

@ -56,6 +56,7 @@ struct hb_ot_map_t
unsigned int auto_zwnj : 1;
unsigned int auto_zwj : 1;
unsigned int random : 1;
unsigned int per_syllable : 1;
int cmp (const hb_tag_t tag_) const
{ return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; }
@ -66,6 +67,7 @@ struct hb_ot_map_t
unsigned short auto_zwnj : 1;
unsigned short auto_zwj : 1;
unsigned short random : 1;
unsigned short per_syllable : 1;
hb_mask_t mask;
HB_INTERNAL static int cmp (const void *pa, const void *pb)
@ -183,7 +185,8 @@ enum hb_ot_map_feature_flags_t
F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS,
F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK,
F_GLOBAL_SEARCH = 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */
F_RANDOM = 0x0020u /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
F_RANDOM = 0x0020u, /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
F_PER_SYLLABLE = 0x0040u /* Contain lookup application to within syllable. */
};
HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
@ -237,7 +240,8 @@ struct hb_ot_map_builder_t
hb_mask_t mask,
bool auto_zwnj = true,
bool auto_zwj = true,
bool random = false);
bool random = false,
bool per_syllable = false);
struct feature_info_t {
hb_tag_t tag;

View File

@ -109,17 +109,17 @@ indic_features[] =
* These features are applied in order, one at a time, after initial_reordering,
* constrained to the syllable.
*/
{HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('r','p','h','f'), F_MANUAL_JOINERS},
{HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
{HB_TAG('h','a','l','f'), F_MANUAL_JOINERS},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
{HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('r','p','h','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('h','a','l','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
/*
* Other features.
* These features are applied all at once, after final_reordering, constrained
@ -127,12 +127,12 @@ indic_features[] =
* Default Bengali font in Windows for example has intermixed
* lookups for init,pres,abvs,blws features.
*/
{HB_TAG('i','n','i','t'), F_MANUAL_JOINERS},
{HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('i','n','i','t'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
};
/*
@ -183,10 +183,10 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
/* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables_indic);
map->enable_feature (HB_TAG('l','o','c','l'));
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it, it's typically at the beginning. */
map->enable_feature (HB_TAG('c','c','m','p'));
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
unsigned int i = 0;
@ -201,8 +201,6 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
for (; i < INDIC_NUM_FEATURES; i++)
map->add_feature (indic_features[i]);
map->add_gsub_pause (_hb_clear_syllables);
}
static void

View File

@ -45,11 +45,11 @@ khmer_features[] =
* These features are applied all at once, before reordering, constrained
* to the syllable.
*/
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
{HB_TAG('c','f','a','r'), F_MANUAL_JOINERS},
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('c','f','a','r'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
/*
* Other features.
* These features are applied all at once after clearing syllables.
@ -107,16 +107,10 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
*
* https://github.com/harfbuzz/harfbuzz/issues/974
*/
map->enable_feature (HB_TAG('l','o','c','l'));
map->enable_feature (HB_TAG('c','c','m','p'));
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
unsigned int i = 0;
for (; i < KHMER_BASIC_FEATURES; i++)
map->add_feature (khmer_features[i]);
map->add_gsub_pause (_hb_clear_syllables);
for (; i < KHMER_NUM_FEATURES; i++)
for (unsigned i = 0; i < KHMER_NUM_FEATURES; i++)
map->add_feature (khmer_features[i]);
}

View File

@ -79,22 +79,20 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
/* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables_myanmar);
map->enable_feature (HB_TAG('l','o','c','l'));
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it, it's typically at the beginning. */
map->enable_feature (HB_TAG('c','c','m','p'));
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
map->add_gsub_pause (reorder_myanmar);
for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
{
map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (nullptr);
}
map->add_gsub_pause (_hb_clear_syllables);
for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
}

View File

@ -115,25 +115,24 @@ collect_features_use (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (setup_syllables_use);
/* "Default glyph pre-processing group" */
map->enable_feature (HB_TAG('l','o','c','l'));
map->enable_feature (HB_TAG('c','c','m','p'));
map->enable_feature (HB_TAG('n','u','k','t'));
map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ);
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('n','u','k','t'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
/* "Reordering group" */
map->add_gsub_pause (_hb_clear_substitution_flags);
map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (record_rphf_use);
map->add_gsub_pause (_hb_clear_substitution_flags);
map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (record_pref_use);
/* "Orthographic unit shaping group" */
for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ);
map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (reorder_use);
map->add_gsub_pause (_hb_clear_syllables);
/* "Topographical features" */
for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)

View File

@ -11,3 +11,4 @@
../fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf;;U+0B2C,U+0B55,U+0B3E;[uni0B2C=0+641|uni0B55=0+0|uni0B3E=0+253]
../fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf;;U+0B2C,U+0B3E,U+0B55;[uni0B2C=0+641|uni0B3E=0+253|uni0B55=0+0]
../fonts/e2b17207c4b7ad78d843e1b0c4d00b09398a1137.ttf;;U+0BAA,U+0BAA,U+0BCD;[pa-tamil=0+778|pa-tamil.001=1+778|pulli-tamil=1@-385,0+0]
../fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf;;U+0926,U+093F,U+0938,U+0902,U+092C,U+0930;[isigndeva=0+266|dadeva=0+541|sadeva=2+709|anusvaradeva=2@0,-1+0|badeva=4+537|radeva=5+436]