[USE] Implement topographical features for non-Arabic-joining scripts

This works per-syllable as per the spec, but we think it should be per
spacing/base/??? glyph instead.
This commit is contained in:
Behdad Esfahbod 2015-07-22 13:27:06 +01:00
parent ecb0b24ef3
commit 9cd59db1af
1 changed files with 80 additions and 7 deletions

View File

@ -66,6 +66,14 @@ arabic_features[] =
HB_TAG('f','i','n','2'),
HB_TAG('f','i','n','3'),
};
/* Same order as arabic_features. Don't need Syriac stuff.*/
enum joining_form_t {
ISOL,
INIT,
MEDI,
FINA,
_NONE
};
static const hb_tag_t
other_features[] =
{
@ -136,7 +144,6 @@ collect_features_use (hb_ot_shape_planner_t *plan)
/* "Topographical features" */
for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
map->add_feature (arabic_features[i], 1, F_NONE);
map->add_gsub_pause (NULL);
/* "Standard typographic presentation" and "Positional feature application" */
@ -264,14 +271,9 @@ setup_masks_use (const hb_ot_shape_plan_t *plan,
}
static void
setup_syllables (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
setup_rphf_mask (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer)
{
find_syllables (buffer);
/* Setup 'rphf' mask. */
const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
hb_mask_t mask = use_plan->rphf_mask;
@ -287,6 +289,77 @@ setup_syllables (const hb_ot_shape_plan_t *plan,
}
}
static void
setup_topographical_masks (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer)
{
ASSERT_STATIC (INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4);
hb_mask_t masks[4], all_masks = 0;
for (unsigned int i = 0; i < 4; i++)
{
masks[i] = plan->map.get_1_mask (arabic_features[i]);
if (masks[i] == plan->map.get_global_mask ())
masks[i] = 0;
all_masks |= masks[i];
}
if (!all_masks)
return;
hb_mask_t other_masks = ~all_masks;
unsigned int last_start = 0;
joining_form_t last_form = _NONE;
hb_glyph_info_t *info = buffer->info;
foreach_syllable (buffer, start, end)
{
syllable_type_t syllable_type = (syllable_type_t) (info[start].syllable() & 0x0F);
switch (syllable_type)
{
case independent_cluster:
case symbol_cluster:
/* These don't join. Nothing to do. */
last_form = _NONE;
break;
case virama_terminated_cluster:
case consonant_cluster:
case vowel_cluster:
case number_joiner_terminated_cluster:
case numeral_cluster:
case broken_cluster:
bool join = last_form == FINA || last_form == ISOL;
if (join)
{
/* Fixup previous syllable's form. */
last_form = last_form == FINA ? MEDI : INIT;
for (unsigned int i = last_start; i < start; i++)
info[i].mask = (info[i].mask & other_masks) | masks[last_form];
}
/* Form for this syllable. */
last_form = join ? FINA : ISOL;
for (unsigned int i = start; i < end; i++)
info[i].mask = (info[i].mask & other_masks) | masks[last_form];
break;
}
last_start = start;
}
}
static void
setup_syllables (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
find_syllables (buffer);
setup_rphf_mask (plan, buffer);
setup_topographical_masks (plan, buffer);
}
static void
clear_substitution_flags (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,