diff options
Diffstat (limited to 'text/shape-build.c')
| -rw-r--r-- | text/shape-build.c | 229 |
1 files changed, 189 insertions, 40 deletions
diff --git a/text/shape-build.c b/text/shape-build.c index aa653d8..559517e 100644 --- a/text/shape-build.c +++ b/text/shape-build.c @@ -3,6 +3,7 @@ * masks and stages), what the section carries, and a check of it against * HarfBuzz on random runs. */ #include "shape-build.h" +#include "syllabic.h" #include "text.h" #include <hb-ot.h> #include <stdlib.h> @@ -25,7 +26,8 @@ typedef struct { uint32_t mask, one_mask; bool auto_zwnj, auto_zwj, random, per_syllable, needs_fallback; } FeatureMap; -typedef struct { unsigned index; uint32_t mask; bool auto_zwnj, auto_zwj, random, per_syllable; } LookupMap; +/* A lookup to run, or (index VEGA_STEP_PAUSE) the pause that ends a stage. */ +typedef struct { unsigned index; uint32_t mask; bool auto_zwnj, auto_zwj, random, per_syllable; unsigned pause; } LookupMap; typedef struct { hb_face_t *face; @@ -33,6 +35,7 @@ typedef struct { hb_tag_t chosen_script[2]; FeatureInfo infos[MAX_FEATURES]; unsigned info_count, current_stage[2]; + unsigned pause[2][MAX_STAGES]; /* what ends each stage: VEGA_PAUSE_..., or 0 */ bool is_simple; /* compiled */ FeatureMap features[MAX_FEATURES]; @@ -40,6 +43,7 @@ typedef struct { uint32_t global_mask; LookupMap *lookups[2]; unsigned lookup_count[2]; + unsigned stage_first[2][MAX_STAGES], stage_end[2][MAX_STAGES]; /* each stage's lookups */ } Map; static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS}; @@ -51,7 +55,10 @@ static void add_feature(Map *m, hb_tag_t tag, unsigned flags, unsigned value) { m->info_count++; } static void enable_feature(Map *m, hb_tag_t tag, unsigned flags, unsigned value) { add_feature(m, tag, flags | F_GLOBAL, value); } -static void add_gsub_pause(Map *m) { m->current_stage[0]++; } +static void add_gsub_pause(Map *m, unsigned pause) { + if (m->current_stage[0] < MAX_STAGES) m->pause[0][m->current_stage[0]] = pause; + m->current_stage[0]++; +} static bool has_feature(const Map *m, hb_tag_t tag) { for (int t = 0; t < 2; ++t) @@ -97,6 +104,17 @@ static uint32_t one_mask(const Map *m, const char *tag) { return f ? f->one_mask : 0; } +static bool push_lookup(Map *m, int table, LookupMap l, unsigned *allocated) { + if (m->lookup_count[table] == *allocated) { + *allocated = *allocated ? 2 * *allocated : 64; + LookupMap *grown = realloc(m->lookups[table], *allocated * sizeof(*grown)); + if (!grown) return false; + m->lookups[table] = grown; + } + m->lookups[table][m->lookup_count[table]++] = l; + return true; +} + static bool add_lookups(Map *m, int table, unsigned feature_index, uint32_t mask, bool auto_zwnj, bool auto_zwj, bool random, bool per_syllable, unsigned *allocated) { unsigned table_lookup_count = hb_ot_layout_table_get_lookup_count(m->face, table_tags[table]); @@ -104,17 +122,11 @@ static bool add_lookups(Map *m, int table, unsigned feature_index, uint32_t mask do { len = 32; hb_ot_layout_feature_get_lookups(m->face, table_tags[table], feature_index, offset, &len, indices); - for (unsigned i = 0; i < len; ++i) { - if (indices[i] >= table_lookup_count) continue; - if (m->lookup_count[table] == *allocated) { - *allocated = *allocated ? 2 * *allocated : 64; - LookupMap *grown = realloc(m->lookups[table], *allocated * sizeof(*grown)); - if (!grown) return false; - m->lookups[table] = grown; - } - m->lookups[table][m->lookup_count[table]++] = - (LookupMap){indices[i], mask, auto_zwnj, auto_zwj, random, per_syllable}; - } + for (unsigned i = 0; i < len; ++i) + if (indices[i] < table_lookup_count && + !push_lookup(m, table, (LookupMap){indices[i], mask, auto_zwnj, auto_zwj, random, per_syllable, 0}, + allocated)) + return false; offset += len; } while (len == 32); return true; @@ -254,9 +266,9 @@ static bool compile_map(Map *m) { map->one_mask = (1u << map->shift) & map->mask; } if (m->is_simple) qsort(m->features, m->feature_count, sizeof(*m->features), by_tag); - /* The final pause, then each stage's lookups: sorted, duplicates merged. */ - m->current_stage[0]++; - m->current_stage[1]++; + /* The final pause, then each stage's lookups: sorted, duplicates merged, + * the stage's pause after them. */ + if (++m->current_stage[0] > MAX_STAGES || ++m->current_stage[1] > MAX_STAGES) return false; for (int t = 0; t < 2; ++t) { unsigned allocated = 0, last = 0; for (unsigned stage = 0; stage < m->current_stage[t]; ++stage) { @@ -284,6 +296,12 @@ static bool compile_map(Map *m) { } m->lookup_count[t] = j + 1; } + m->stage_first[t][stage] = last; + m->stage_end[t][stage] = m->lookup_count[t]; + if (m->pause[t][stage] && + !push_lookup(m, t, (LookupMap){VEGA_STEP_PAUSE, 0, false, false, false, false, m->pause[t][stage]}, + &allocated)) + return false; last = m->lookup_count[t]; } } @@ -316,9 +334,9 @@ static int categorize(uint32_t script, hb_tag_t gsub_script) { if (script == TAG("Syrc") || script == TAG("Thai") || script == TAG("Laoo") || script == TAG("Khmr") || script == TAG("Qaag")) return -1; - if (listed(indic_scripts, sizeof(indic_scripts) / sizeof(*indic_scripts), script) || - listed(use_scripts, sizeof(use_scripts) / sizeof(*use_scripts), script)) - return dflt ? VEGA_SHAPER_DEFAULT : -1; + if (listed(indic_scripts, sizeof(indic_scripts) / sizeof(*indic_scripts), script)) + return dflt ? VEGA_SHAPER_DEFAULT : (gsub_script & 0xFF) == '3' ? -1 : VEGA_SHAPER_INDIC; + if (listed(use_scripts, sizeof(use_scripts) / sizeof(*use_scripts), script)) return dflt ? VEGA_SHAPER_DEFAULT : -1; if (script == TAG("Mymr")) return dflt || gsub_script == TAG("mymr") ? VEGA_SHAPER_DEFAULT : -1; return VEGA_SHAPER_DEFAULT; } @@ -330,14 +348,26 @@ static bool has_table(hb_face_t *face, hb_tag_t tag) { return has; } +typedef struct { unsigned first, count; } Stage; typedef struct { uint32_t script; int direction, native, shaper, flags; uint32_t global_mask, kern_mask, masks[VEGA_PLAN_MASKS]; LookupMap *lookups[2]; unsigned lookup_count[2]; + unsigned shaper_flags; + Stage stages[VEGA_PLAN_STAGES]; } Plan; +/* The GSUB stage a feature is in (hb_ot_map_t::get_stage_lookups), for a + * shaper's would-substitute questions. */ +static Stage stage_of(const Map *m, const char *tag) { + const FeatureMap *f = find_feature(m, TAG(tag)); + if (!f || f->stage[0] >= m->current_stage[0]) return (Stage){0, 0}; + unsigned first = m->stage_first[0][f->stage[0]]; + return (Stage){first, m->stage_end[0][f->stage[0]] - first}; +} + /* What HarfBuzz makes of the font's kern table (hb-ot-kern-table.hh): one * with subtables that pass its checks (data), Apple's state machines among * them (machine), cross-stream kerning (cross); and whether it has what @@ -415,7 +445,7 @@ static bool plan_for(hb_face_t *face, uint32_t script_tag, int direction, Plan * /* hb_ot_shape_collect_features */ m->is_simple = true; enable_feature(m, TAG("rvrn"), F_NONE, 1); - add_gsub_pause(m); + add_gsub_pause(m, 0); if (direction == VEGA_SHAPE_LTR) { enable_feature(m, TAG("ltra"), F_NONE, 1); enable_feature(m, TAG("ltrm"), F_NONE, 1); @@ -434,23 +464,57 @@ static bool plan_for(hb_face_t *face, uint32_t script_tag, int direction, Plan * if (shaper == VEGA_SHAPER_ARABIC) { m->is_simple = false; enable_feature(m, TAG("stch"), F_NONE, 1); - add_gsub_pause(m); /* record_stch */ + add_gsub_pause(m, 0); /* record_stch */ enable_feature(m, TAG("ccmp"), F_MANUAL_ZWJ, 1); enable_feature(m, TAG("locl"), F_MANUAL_ZWJ, 1); - add_gsub_pause(m); + add_gsub_pause(m, 0); for (int i = 0; i < 7; ++i) { bool syriac = arabic_features[i][3] == '2' || arabic_features[i][3] == '3'; add_feature(m, TAG(arabic_features[i]), F_MANUAL_ZWJ | (script == HB_SCRIPT_ARABIC && !syriac ? F_HAS_FALLBACK : 0), 1); - add_gsub_pause(m); + add_gsub_pause(m, 0); } enable_feature(m, TAG("rlig"), F_MANUAL_ZWJ | F_HAS_FALLBACK, 1); - if (script == HB_SCRIPT_ARABIC) add_gsub_pause(m); /* arabic_fallback_shape */ + if (script == HB_SCRIPT_ARABIC) add_gsub_pause(m, 0); /* arabic_fallback_shape */ enable_feature(m, TAG("calt"), F_MANUAL_ZWJ, 1); - if (!has_feature(m, TAG("rclt"))) add_gsub_pause(m); + if (!has_feature(m, TAG("rclt"))) add_gsub_pause(m, 0); enable_feature(m, TAG("liga"), F_MANUAL_ZWJ, 1); enable_feature(m, TAG("clig"), F_MANUAL_ZWJ, 1); enable_feature(m, TAG("mset"), F_MANUAL_ZWJ, 1); } + /* hb-ot-shaper-indic.cc: syllables found before any lookup; locl and + * ccmp; the initial reordering; the basic features one stage each; the + * final reordering; the rest. */ + static const struct { const char *tag; unsigned flags; } indic_features[17] = { + {"nukt", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"akhn", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"rphf", F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"rkrf", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"pref", F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"blwf", F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"abvf", F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"half", F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"pstf", F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"vatu", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"cjct", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"init", F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"pres", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"abvs", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"blws", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"psts", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}, + {"haln", F_GLOBAL | F_MANUAL_ZWNJ | F_MANUAL_ZWJ | F_PER_SYLLABLE}}; + if (shaper == VEGA_SHAPER_INDIC) { + m->is_simple = false; + add_gsub_pause(m, VEGA_PAUSE_SYLLABLES); + enable_feature(m, TAG("locl"), F_PER_SYLLABLE, 1); + enable_feature(m, TAG("ccmp"), F_PER_SYLLABLE, 1); + add_gsub_pause(m, VEGA_PAUSE_INITIAL_REORDERING); + for (int i = 0; i < 11; ++i) { + add_feature(m, TAG(indic_features[i].tag), indic_features[i].flags, 1); + add_gsub_pause(m, 0); + } + add_gsub_pause(m, VEGA_PAUSE_FINAL_REORDERING); + for (int i = 11; i < 17; ++i) add_feature(m, TAG(indic_features[i].tag), indic_features[i].flags, 1); + } if (shaper == VEGA_SHAPER_HANGUL) { m->is_simple = false; add_feature(m, TAG("ljmo"), F_NONE, 1); @@ -464,9 +528,14 @@ static bool plan_for(hb_face_t *face, uint32_t script_tag, int direction, Plan * add_feature(m, TAG(common[i]), F_GLOBAL | (i == 4 || i == 5 ? F_MANUAL_ZWNJ | F_MANUAL_ZWJ : 0), 1); static const char *const horizontal[] = {"calt", "clig", "curs", "dist", "kern", "liga", "rclt"}; for (int i = 0; i < 7; ++i) add_feature(m, TAG(horizontal[i]), F_GLOBAL | (i == 4 ? F_HAS_FALLBACK : 0), 1); - /* Hangul turns calt off: fonts put jamo lookups there. */ + /* Hangul turns calt off: fonts put jamo lookups there. Indic turns liga + * off, and is done with syllables after GSUB. */ if (shaper == VEGA_SHAPER_HANGUL) add_feature(m, TAG("calt"), F_GLOBAL, 0); - if (!compile_map(m)) FAIL("out of memory"); + if (shaper == VEGA_SHAPER_INDIC) { + add_feature(m, TAG("liga"), F_GLOBAL, 0); + add_gsub_pause(m, VEGA_PAUSE_CLEAR_SYLLABLES); + } + if (!compile_map(m)) FAIL("out of memory, or more than %d stages", MAX_STAGES); /* hb_ot_shape_planner_t::compile */ const FeatureMap *kern = find_feature(m, TAG("kern")); @@ -476,8 +545,9 @@ static bool plan_for(hb_face_t *face, uint32_t script_tag, int direction, Plan * bool apply_kern = (!has_gpos_kern || !apply_gpos) && kern_table.data; if (apply_kern && (kern_table.other || kern_table.cross)) FAIL("%s: the font's kern table has more than pairs (state machines, classes, cross-stream kerning)", name); - /* Hangul's shaper neither zeroes marks nor places them without GPOS. */ - bool script_marks = shaper != VEGA_SHAPER_HANGUL; + /* Hangul's and Indic's shapers neither zero marks nor place them + * without GPOS. */ + bool script_marks = shaper != VEGA_SHAPER_HANGUL && shaper != VEGA_SHAPER_INDIC; bool adjust = !apply_gpos && (!apply_kern || !kern_table.cross), fallback_marks = adjust && script_marks; if (shaper == VEGA_SHAPER_ARABIC) { if (one_mask(m, "stch")) FAIL("%s: the font stretches (stch)", name); @@ -499,15 +569,26 @@ static bool plan_for(hb_face_t *face, uint32_t script_tag, int direction, Plan * (apply_kern ? VEGA_PLAN_KERN : 0) | (fallback_marks ? VEGA_PLAN_FALLBACK_MARKS : 0) | (adjust ? VEGA_PLAN_ADJUST_ZEROING : 0), m->global_mask, kern ? kern->one_mask : 0, {0}, {m->lookups[0], m->lookups[1]}, - {m->lookup_count[0], m->lookup_count[1]}}; - for (int i = 0; i < 7; ++i) plan->masks[VEGA_MASK_ISOL + i] = one_mask(m, arabic_features[i]); + {m->lookup_count[0], m->lookup_count[1]}, 0, {{0, 0}}}; plan->masks[VEGA_MASK_RTLM] = one_mask(m, "rtlm"); plan->masks[VEGA_MASK_FRAC] = frac; plan->masks[VEGA_MASK_NUMR] = numr; plan->masks[VEGA_MASK_DNOM] = dnom; - plan->masks[VEGA_MASK_LJMO] = one_mask(m, "ljmo"); - plan->masks[VEGA_MASK_VJMO] = one_mask(m, "vjmo"); - plan->masks[VEGA_MASK_TJMO] = one_mask(m, "tjmo"); + if (shaper == VEGA_SHAPER_ARABIC) + for (int i = 0; i < 7; ++i) plan->masks[VEGA_MASK_ISOL + i] = one_mask(m, arabic_features[i]); + if (shaper == VEGA_SHAPER_HANGUL) { + plan->masks[VEGA_MASK_LJMO] = one_mask(m, "ljmo"); + plan->masks[VEGA_MASK_VJMO] = one_mask(m, "vjmo"); + plan->masks[VEGA_MASK_TJMO] = one_mask(m, "tjmo"); + } + if (shaper == VEGA_SHAPER_INDIC) { + /* the masks of the features set glyph by glyph (not global ones) */ + static const char *const masked[] = {"rphf", "pref", "blwf", "abvf", "half", "pstf", "init"}; + for (int i = 0; i < 7; ++i) plan->masks[VEGA_MASK_RPHF + i] = one_mask(m, masked[i]); + static const char *const staged[VEGA_PLAN_STAGES] = {"rphf", "pref", "blwf", "pstf", "vatu"}; + for (int i = 0; i < VEGA_PLAN_STAGES; ++i) plan->stages[i] = stage_of(m, staged[i]); + if ((m->chosen_script[0] & 0xFF) != '2') plan->shaper_flags |= VEGA_INDIC_OLD_SPEC; + } free(m); return true; fail: @@ -661,6 +742,13 @@ bool vega_shaping_compile(hb_face_t *face, const uint32_t *scripts, size_t scrip put32(&o, p->lookup_count[t]); step += p->lookup_count[t]; } + put32(&o, p->shaper_flags); + for (int k = 0; k < VEGA_PLAN_STAGES; ++k) { + put16(&o, p->stages[k].first); + put16(&o, p->stages[k].count); + put32(&o, 0); + } + put32(&o, 0); } set32(&o, 56, step); set32(&o, 60, (uint32_t)o.size); @@ -669,10 +757,11 @@ bool vega_shaping_compile(hb_face_t *face, const uint32_t *scripts, size_t scrip for (unsigned k = 0; k < plans[i].lookup_count[t]; ++k) { const LookupMap *l = &plans[i].lookups[t][k]; put16(&o, l->index); - unsigned char flags[2] = {(unsigned char)((l->auto_zwnj ? VEGA_STEP_AUTO_ZWNJ : 0) | - (l->auto_zwj ? VEGA_STEP_AUTO_ZWJ : 0) | - (l->random ? VEGA_STEP_RANDOM : 0) | - (l->per_syllable ? VEGA_STEP_PER_SYLLABLE : 0)), + unsigned char flags[2] = {(unsigned char)(l->index == VEGA_STEP_PAUSE ? l->pause + : (l->auto_zwnj ? VEGA_STEP_AUTO_ZWNJ : 0) | + (l->auto_zwj ? VEGA_STEP_AUTO_ZWJ : 0) | + (l->random ? VEGA_STEP_RANDOM : 0) | + (l->per_syllable ? VEGA_STEP_PER_SYLLABLE : 0)), 0}; put(&o, flags, 2); put32(&o, l->mask); @@ -708,7 +797,8 @@ bool vega_shaping_compile(hb_face_t *face, const uint32_t *scripts, size_t scrip if (hb_font_get_nominal_glyph(font, u, &g)) hb_set_add(glyphs, g); } for (size_t i = 0; i < plan_count; ++i) - for (unsigned k = 0; k < plans[i].lookup_count[0]; ++k) hb_set_add(lookups, plans[i].lookups[0][k].index); + for (unsigned k = 0; k < plans[i].lookup_count[0]; ++k) + if (plans[i].lookups[0][k].index != VEGA_STEP_PAUSE) hb_set_add(lookups, plans[i].lookups[0][k].index); hb_ot_layout_lookups_substitute_closure(face, lookups, glyphs); hb_set_destroy(wanted); hb_set_destroy(lookups); @@ -763,6 +853,46 @@ static uint32_t jamo(Random *r, const Pool *p, uint32_t first, uint32_t count) { return p->count && below(r, 2) ? pick(r, p) : first + below(r, count); } +/* An Indic syllable the ways text spells one (hb-ot-shaper-indic.cc): + * consonants joined by viramas (a joiner by some), a Ra and virama first + * for a reph, nuktas, matras, syllable modifiers, a virama at the end; a + * vowel with its modifiers. indic holds the script's consonants, Ra, + * viramas, nuktas, matras, modifiers and vowels. */ +enum { INDIC_CONSONANTS, INDIC_RA, INDIC_HALANTS, INDIC_NUKTAS, INDIC_MATRAS, INDIC_MODIFIERS, INDIC_VOWELS, INDIC_POOLS }; +static size_t indic_syllable(Random *r, const Pool *indic, uint32_t *text, size_t n) { + const Pool *c = &indic[INDIC_CONSONANTS], *ra = &indic[INDIC_RA], *h = &indic[INDIC_HALANTS], + *nukta = &indic[INDIC_NUKTAS], *m = &indic[INDIC_MATRAS], *sm = &indic[INDIC_MODIFIERS], + *v = &indic[INDIC_VOWELS]; + if (!c->count || !h->count) return n; + if (ra->count && !below(r, 4)) { + text[n++] = pick(r, ra); + text[n++] = pick(r, h); + if (!below(r, 8)) text[n++] = 0x200D; + } + if (v->count && !below(r, 6)) { + text[n++] = pick(r, v); + if (nukta->count && !below(r, 8)) text[n++] = pick(r, nukta); + } else + for (unsigned k = 0, count = 1 + below(r, 3); k < count; ++k) { + text[n++] = ra->count && !below(r, 5) ? pick(r, ra) : pick(r, c); + if (nukta->count && !below(r, 6)) text[n++] = pick(r, nukta); + if (k + 1 == count) break; + unsigned joiner = below(r, 8); + if (joiner == 0) text[n++] = 0x200D; + text[n++] = pick(r, h); + if (joiner == 1) text[n++] = 0x200D; + if (joiner == 2) text[n++] = 0x200C; + } + if (m->count && below(r, 3)) { + text[n++] = pick(r, m); + if (!below(r, 8)) text[n++] = pick(r, m); + } + if (sm->count && !below(r, 4)) text[n++] = pick(r, sm); + if (!below(r, 10)) text[n++] = pick(r, h); + if (!below(r, 12)) text[n++] = below(r, 2) ? 0x200C : 0x200D; + return n; +} + /* A Hangul syllable the ways text spells one (hb-ot-shaper-hangul.cc): jamo * in the orders that compose (L V, L V T, LV T), a syllable whole, jamo in * any order; now and then a tone mark after. jamo holds the font's L, V @@ -805,8 +935,9 @@ void vega_shaping_check(hb_font_t *font, const VegaShaping *s, uint32_t script, /* Letters of the script, marks it can take (its own and inherited * ones), the rest of its characters and Common's (spaces, digits, * punctuation), and those whose glyphs some substitution starts from. */ - Pool letters = {0}, marks = {0}, others = {0}, hot = {0}, jamo_pools[3] = {{0}}; + Pool letters = {0}, marks = {0}, others = {0}, hot = {0}, jamo_pools[3] = {{0}}, indic[INDIC_POOLS] = {{0}}; bool hangul = script == HB_TAG('H', 'a', 'n', 'g'); + bool syllabic = listed(indic_scripts, sizeof(indic_scripts) / sizeof(*indic_scripts), script); hb_set_t *inputs = hb_set_create(); uint32_t common = HB_TAG('Z', 'y', 'y', 'y'), inherited = HB_TAG('Z', 'i', 'n', 'h'); for (unsigned t = 0; t < s->lookup_count[0]; ++t) @@ -820,6 +951,19 @@ void vega_shaping_check(hb_font_t *font, const VegaShaping *s, uint32_t script, if (hangul && ((code >= 0x1100 && code <= 0x115F) || (code >= 0xA960 && code <= 0xA97C))) pool_add(&jamo_pools[0], code); if (hangul && ((code >= 0x1160 && code <= 0x11A7) || (code >= 0xD7B0 && code <= 0xD7C6))) pool_add(&jamo_pools[1], code); if (hangul && ((code >= 0x11A8 && code <= 0x11FF) || (code >= 0xD7CB && code <= 0xD7FB))) pool_add(&jamo_pools[2], code); + if (syllabic && (of == script || of == inherited)) { + int pool = -1; + switch (vega_indic_categories(code) & 0xFF) { + case VEGA_OT_C: case VEGA_OT_CS: pool = INDIC_CONSONANTS; break; + case VEGA_OT_RA: pool = INDIC_RA; break; + case VEGA_OT_H: pool = INDIC_HALANTS; break; + case VEGA_OT_N: pool = INDIC_NUKTAS; break; + case VEGA_OT_M: case VEGA_OT_MPST: pool = INDIC_MATRAS; break; + case VEGA_OT_SM: case VEGA_OT_A: pool = INDIC_MODIFIERS; break; + case VEGA_OT_V: pool = INDIC_VOWELS; break; + } + if (pool >= 0) pool_add(&indic[pool], code); + } if (mark && (of == script || of == inherited)) pool_add(&marks, code); else if (!mark && of == script && c >= VEGA_LU && c <= VEGA_LO) pool_add(&letters, code); else if (!mark && (of == script || of == common) && c != VEGA_ZL && c != VEGA_ZP) pool_add(&others, code); @@ -851,6 +995,10 @@ void vega_shaping_check(hb_font_t *font, const VegaShaping *s, uint32_t script, n = hangul_syllable(&random, jamo_pools, text, n); continue; } + if (syllabic && below(&random, 3)) { + n = indic_syllable(&random, indic, text, n); + continue; + } text[n++] = hot.count && below(&random, 3) == 0 ? pick(&random, &hot) : pick(&random, &letters); if (marks.count && below(&random, 100) < mark_rate) { text[n++] = pick(&random, &marks); @@ -916,4 +1064,5 @@ void vega_shaping_check(hb_font_t *font, const VegaShaping *s, uint32_t script, free(others.items); free(hot.items); for (int k = 0; k < 3; ++k) free(jamo_pools[k].items); + for (int k = 0; k < INDIC_POOLS; ++k) free(indic[k].items); } |
