[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 () : matcher_t () :
lookup_props (0), lookup_props (0),
mask (-1),
ignore_zwnj (false), ignore_zwnj (false),
ignore_zwj (false), ignore_zwj (false),
mask (-1), per_syllable (false),
syllable {0}, syllable {0},
match_func (nullptr), match_func (nullptr),
match_data (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_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
void set_mask (hb_mask_t mask_) { mask = mask_; } 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_, void set_match_func (match_func_t match_func_,
const void *match_data_) const void *match_data_)
{ match_func = match_func_; match_data = match_data_; } { match_func = match_func_; match_data = match_data_; }
@ -467,9 +469,10 @@ struct hb_ot_apply_context_t :
protected: protected:
unsigned int lookup_props; unsigned int lookup_props;
hb_mask_t mask;
bool ignore_zwnj; bool ignore_zwnj;
bool ignore_zwj; bool ignore_zwj;
hb_mask_t mask; bool per_syllable;
uint8_t syllable; uint8_t syllable;
match_func_t match_func; match_func_t match_func;
const void *match_data; const void *match_data;
@ -488,6 +491,7 @@ struct hb_ot_apply_context_t :
/* Ignore ZWJ if we are matching context, or asked to. */ /* Ignore ZWJ if we are matching context, or asked to. */
matcher.set_ignore_zwj (context_match || c->auto_zwj); matcher.set_ignore_zwj (context_match || c->auto_zwj);
matcher.set_mask (context_match ? -1 : c->lookup_mask); matcher.set_mask (context_match ? -1 : c->lookup_mask);
matcher.set_per_syllable (c->per_syllable);
} }
void set_lookup_props (unsigned int lookup_props) void set_lookup_props (unsigned int lookup_props)
{ {
@ -634,6 +638,7 @@ struct hb_ot_apply_context_t :
bool has_glyph_classes; bool has_glyph_classes;
bool auto_zwnj; bool auto_zwnj;
bool auto_zwj; bool auto_zwj;
bool per_syllable;
bool random; bool random;
uint32_t random_state; uint32_t random_state;
@ -662,6 +667,7 @@ struct hb_ot_apply_context_t :
has_glyph_classes (gdef.has_glyph_classes ()), has_glyph_classes (gdef.has_glyph_classes ()),
auto_zwnj (true), auto_zwnj (true),
auto_zwj (true), auto_zwj (true),
per_syllable (false),
random (false), random (false),
random_state (1) { init_iters (); } 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_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_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_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_random (bool random_) { random = random_; }
void set_recurse_func (recurse_func_t func) { recurse_func = func; } void set_recurse_func (recurse_func_t func) { recurse_func = func; }
void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } 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_zwj (lookups[table_index][i].auto_zwj);
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj); c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
c.set_random (lookups[table_index][i].random); c.set_random (lookups[table_index][i].random);
c.set_per_syllable (lookups[table_index][i].per_syllable);
apply_string<Proxy> (&c, apply_string<Proxy> (&c,
proxy.table.get_lookup (lookup_index), proxy.table.get_lookup (lookup_index),

View File

@ -172,17 +172,6 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
return 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 */ /* unicode_props */

View File

@ -117,7 +117,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
hb_mask_t mask, hb_mask_t mask,
bool auto_zwnj, bool auto_zwnj,
bool auto_zwj, bool auto_zwj,
bool random) bool random,
bool per_syllable)
{ {
unsigned int lookup_indices[32]; unsigned int lookup_indices[32];
unsigned int offset, len; 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_zwnj = auto_zwnj;
lookup->auto_zwj = auto_zwj; lookup->auto_zwj = auto_zwj;
lookup->random = random; lookup->random = random;
lookup->per_syllable = per_syllable;
} }
offset += len; 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_zwnj = !(info->flags & F_MANUAL_ZWNJ);
map->auto_zwj = !(info->flags & F_MANUAL_ZWJ); map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
map->random = !!(info->flags & F_RANDOM); map->random = !!(info->flags & F_RANDOM);
map->per_syllable = !!(info->flags & F_PER_SYLLABLE);
if ((info->flags & F_GLOBAL) && info->max_value == 1) { if ((info->flags & F_GLOBAL) && info->max_value == 1) {
/* Uses the global bit */ /* Uses the global bit */
map->shift = global_bit_shift; 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].mask,
m.features[i].auto_zwnj, m.features[i].auto_zwnj,
m.features[i].auto_zwj, m.features[i].auto_zwj,
m.features[i].random); m.features[i].random,
m.features[i].per_syllable);
/* Sort lookups and merge duplicates */ /* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].length) 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_zwnj : 1;
unsigned int auto_zwj : 1; unsigned int auto_zwj : 1;
unsigned int random : 1; unsigned int random : 1;
unsigned int per_syllable : 1;
int cmp (const hb_tag_t tag_) const int cmp (const hb_tag_t tag_) const
{ return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; } { 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_zwnj : 1;
unsigned short auto_zwj : 1; unsigned short auto_zwj : 1;
unsigned short random : 1; unsigned short random : 1;
unsigned short per_syllable : 1;
hb_mask_t mask; hb_mask_t mask;
HB_INTERNAL static int cmp (const void *pa, const void *pb) 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_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS,
F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK, 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_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); 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, hb_mask_t mask,
bool auto_zwnj = true, bool auto_zwnj = true,
bool auto_zwj = true, bool auto_zwj = true,
bool random = false); bool random = false,
bool per_syllable = false);
struct feature_info_t { struct feature_info_t {
hb_tag_t tag; 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, * These features are applied in order, one at a time, after initial_reordering,
* constrained to the syllable. * constrained to the syllable.
*/ */
{HB_TAG('n','u','k','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}, {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('r','p','h','f'), F_MANUAL_JOINERS}, {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('h','a','l','f'), F_MANUAL_JOINERS}, {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
/* /*
* Other features. * Other features.
* These features are applied all at once, after final_reordering, constrained * 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 * Default Bengali font in Windows for example has intermixed
* lookups for init,pres,abvs,blws features. * lookups for init,pres,abvs,blws features.
*/ */
{HB_TAG('i','n','i','t'), F_MANUAL_JOINERS}, {HB_TAG('i','n','i','t'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS}, {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. */ /* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables_indic); 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 /* 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. */ * 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; unsigned int i = 0;
@ -201,8 +201,6 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
for (; i < INDIC_NUM_FEATURES; i++) for (; i < INDIC_NUM_FEATURES; i++)
map->add_feature (indic_features[i]); map->add_feature (indic_features[i]);
map->add_gsub_pause (_hb_clear_syllables);
} }
static void static void

View File

@ -45,11 +45,11 @@ khmer_features[] =
* These features are applied all at once, before reordering, constrained * These features are applied all at once, before reordering, constrained
* to the syllable. * to the syllable.
*/ */
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('c','f','a','r'), F_MANUAL_JOINERS}, {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
/* /*
* Other features. * Other features.
* These features are applied all at once after clearing syllables. * 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 * https://github.com/harfbuzz/harfbuzz/issues/974
*/ */
map->enable_feature (HB_TAG('l','o','c','l')); map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
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; for (unsigned i = 0; i < KHMER_NUM_FEATURES; i++)
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++)
map->add_feature (khmer_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. */ /* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables_myanmar); 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 /* 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. */ * 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); map->add_gsub_pause (reorder_myanmar);
for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++) 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 (nullptr);
} }
map->add_gsub_pause (_hb_clear_syllables);
for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++) for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ); 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); map->add_gsub_pause (setup_syllables_use);
/* "Default glyph pre-processing group" */ /* "Default glyph pre-processing group" */
map->enable_feature (HB_TAG('l','o','c','l')); map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('c','c','m','p')); map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('n','u','k','t')); map->enable_feature (HB_TAG('n','u','k','t'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ); map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
/* "Reordering group" */ /* "Reordering group" */
map->add_gsub_pause (_hb_clear_substitution_flags); 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 (record_rphf_use);
map->add_gsub_pause (_hb_clear_substitution_flags); 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); map->add_gsub_pause (record_pref_use);
/* "Orthographic unit shaping group" */ /* "Orthographic unit shaping group" */
for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++) 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 (reorder_use);
map->add_gsub_pause (_hb_clear_syllables);
/* "Topographical features" */ /* "Topographical features" */
for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++) 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+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/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/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]