📄 khmer-fc.c
字号:
abvf_p = /*(abvf | abvs | clig | dist | abvm)*/ (pref | pstf | blwf | pres | blws | psts | blwm), pref_p = /*(pref | pres | clig | dist)*/ (abvf | pstf | blwf | blws | abvs | psts | blwm | abvm), default_p = /*(pres | blws | clig | dist | abvm | blwm)*/ (pref | blwf |abvf | pstf | abvs | psts)};/* Below we define how a character in the input string is either in the khmerCharClasses table * (in which case we get its type back), a ZWJ or ZWNJ (two characters that may appear * within the syllable, but are not in the table) we also get their type back, or an unknown object * in which case we get _xx (CC_RESERVED) back */static KhmerCharClassget_char_class (gunichar ch){ if (ch == C_SIGN_ZWJ) return CC_ZERO_WIDTH_J_MARK; if (ch == C_SIGN_ZWNJ) return CC_ZERO_WIDTH_NJ_MARK; if (ch < firstChar || ch > lastChar) return CC_RESERVED; return khmerCharClasses[ch - firstChar];}/* Given an input string of characters and a location in which to start looking * calculate, using the state table, which one is the last character of the syllable * that starts in the starting position. */static glongfind_syllable (const gunichar *chars, glong start, glong char_count){ glong cursor = start; gint8 state = 0; KhmerCharClass charClass; while (cursor < char_count) { charClass = get_char_class (chars[cursor]) & CF_CLASS_MASK; state = khmerStateTable[state][charClass]; if (state < 0) break; cursor += 1; } return cursor;}static const PangoOTFeatureMap gsub_features[] ={ {"ccmp", PANGO_OT_ALL_GLYPHS}, {"locl", PANGO_OT_ALL_GLYPHS}, {"pref", pref}, {"blwf", blwf}, {"abvf", abvf}, {"pstf", pstf}, {"pres", pres}, {"blws", blws}, {"abvs", abvs}, {"psts", psts}, {"clig", clig}, {"calt", PANGO_OT_ALL_GLYPHS}};static const PangoOTFeatureMap gpos_features[] ={ {"dist", dist}, {"blwm", blwm}, {"abvm", abvm}, {"kern", PANGO_OT_ALL_GLYPHS}, {"mark", PANGO_OT_ALL_GLYPHS}, {"mkmk", PANGO_OT_ALL_GLYPHS}};static PangoGlyphget_index (PangoFcFont *fc_font, gunichar wc){ PangoGlyph index = pango_fc_font_get_glyph (fc_font, wc); if (!index) index = PANGO_GET_UNKNOWN_GLYPH ( wc); return index;}static voidkhmer_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, int length, const PangoAnalysis *analysis, PangoGlyphString *glyphs){ PangoFcFont *fc_font; FT_Face face; PangoOTRulesetDescription desc; const PangoOTRuleset *ruleset; PangoOTBuffer *buffer; glong n_chars; gunichar *wcs; const char *p; int i; glong syllable; KhmerCharClass charClass; glong cursor = 0; g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); g_return_if_fail (length >= 0); g_return_if_fail (analysis != NULL); fc_font = PANGO_FC_FONT (font); face = pango_fc_font_lock_face (fc_font); if (!face) return; buffer = pango_ot_buffer_new (fc_font); wcs = g_utf8_to_ucs4_fast (text, length, &n_chars); p = text; /* This loop only exits when we reach the end of a run, which may contain * several syllables. */ while (cursor < n_chars) { /* write a pre vowel or the pre part of a split vowel first * and look out for coeng + ro. RO is the only vowel of type 2, and * therefore the only one that requires saving space before the base. */ glong coengRo = -1; /* There is no Coeng Ro, if found this value will change */ syllable = find_syllable (wcs, cursor, n_chars); for (i = cursor; i < syllable; i += 1) { charClass = get_char_class (wcs[i]); /* if a split vowel, write the pre part. In Khmer the pre part * is the same for all split vowels, same glyph as pre vowel C_VOWEL_E */ if (charClass & CF_SPLIT_VOWEL) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, C_VOWEL_E), pref_p, p - text); break; /* there can be only one vowel */ } /* if a vowel with pos before write it out */ if (charClass & CF_POS_BEFORE) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), pref_p, p - text); break; /* there can be only one vowel */ } /* look for coeng + ro and remember position * works because coeng + ro is always in front of a vowel (if there is a vowel) * and because CC_CONSONANT2 is enough to identify it, as it is the only consonant * with this flag */ if ((charClass & CF_COENG) && (i + 1 < syllable) && ((get_char_class (wcs[i + 1]) & CF_CLASS_MASK) == CC_CONSONANT2)) { coengRo = i; } } /* write coeng + ro if found */ if (coengRo > -1) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, C_COENG), pref_p, p - text); pango_ot_buffer_add_glyph (buffer, get_index (fc_font, C_RO), pref_p, p - text); } /* shall we add a dotted circle? * If in the position in which the base should be (first char in the string) there is * a character that has the Dotted circle flag (a character that cannot be a base) * then write a dotted circle */ if (get_char_class (wcs[cursor]) & CF_DOTTED_CIRCLE) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, C_DOTTED_CIRCLE), default_p, p - text); } /* copy what is left to the output, skipping before vowels and * coeng Ro if they are present */ for (i = cursor; i < syllable; i += 1) { charClass = get_char_class (wcs[i]); /* skip a before vowel, it was already processed */ if (charClass & CF_POS_BEFORE) { p = g_utf8_next_char (p); continue; } /* skip coeng + ro, it was already processed */ if (i == coengRo) { p = g_utf8_next_char (p); i += 1; p = g_utf8_next_char (p); continue; } switch (charClass & CF_POS_MASK) { case CF_POS_ABOVE : pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), abvf_p, p - text); break; case CF_POS_AFTER : pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), pstf_p, p - text); break; case CF_POS_BELOW : pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), blwf_p, p - text); break; default: /* assign the correct flags to a coeng consonant * Consonants of type 3 are taged as Post forms and those type 1 as below forms */ if ((charClass & CF_COENG) && i + 1 < syllable) { if ((get_char_class (wcs[i + 1]) & CF_CLASS_MASK) == CC_CONSONANT3) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), pstf_p, p - text); p = g_utf8_next_char (p); i += 1; pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), pstf_p, p - text); break; } else { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), blwf_p, p - text); p = g_utf8_next_char (p); i += 1; pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), blwf_p, p - text); break; } } /* if a shifter is followed by an above vowel change the shifter to below form, * an above vowel can have two possible positions i + 1 or i + 3 * (position i+1 corresponds to unicode 3, position i+3 to Unicode 4) * and there is an extra rule for C_VOWEL_AA + C_SIGN_NIKAHIT also for two * different positions, right after the shifter or after a vowel (Unicode 4) */ if ((charClass & CF_SHIFTER) && (i + 1 < syllable)) { if (get_char_class (wcs[i + 1]) & CF_ABOVE_VOWEL) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), blwf_p, p - text); break; } if (i + 2 < syllable && (wcs[i + 1] == C_VOWEL_AA) && (wcs[i + 2] == C_SIGN_NIKAHIT) ) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), blwf_p, p - text); break; } if (i + 3 < syllable && (get_char_class (wcs[i + 3]) & CF_ABOVE_VOWEL) ) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), blwf_p, p - text); break; } if (i + 4 < syllable && (wcs[i + 3] == C_VOWEL_AA) && (wcs[i + 4] == C_SIGN_NIKAHIT) ) { pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), blwf_p, p - text); break; } } /* default - any other characters */ pango_ot_buffer_add_glyph (buffer, get_index (fc_font, wcs[i]), default_p, p - text); break; } /* switch */ p = g_utf8_next_char (p); } /* for */ cursor = syllable; /* move the pointer to the start of next syllable */ } /* while */ desc.script = analysis->script; desc.language = analysis->language; desc.n_static_gsub_features = G_N_ELEMENTS (gsub_features); desc.static_gsub_features = gsub_features; desc.n_static_gpos_features = G_N_ELEMENTS (gpos_features); desc.static_gpos_features = gpos_features; /* TODO populate other_features from analysis->extra_attrs */ desc.n_other_features = 0; desc.other_features = NULL; ruleset = pango_ot_ruleset_get_for_description (pango_ot_info_get (face), &desc); pango_ot_ruleset_substitute (ruleset, buffer); pango_ot_ruleset_position (ruleset, buffer); pango_ot_buffer_output (buffer, glyphs); g_free (wcs); pango_ot_buffer_destroy (buffer); pango_fc_font_unlock_face (fc_font);}static voidkhmer_engine_fc_class_init (PangoEngineShapeClass *class){ class->script_shape = khmer_engine_shape;}PANGO_ENGINE_SHAPE_DEFINE_TYPE (KhmerEngineFc, khmer_engine_fc, khmer_engine_fc_class_init, NULL)voidPANGO_MODULE_ENTRY(init) (GTypeModule *module){ khmer_engine_fc_register_type (module);}voidPANGO_MODULE_ENTRY(exit) (void){}voidPANGO_MODULE_ENTRY(list) (PangoEngineInfo **engines, int *n_engines){ *engines = script_engines; *n_engines = G_N_ELEMENTS (script_engines);}PangoEngine *PANGO_MODULE_ENTRY(create) (const char *id){ if (!strcmp (id, SCRIPT_ENGINE_NAME)) return g_object_new (khmer_engine_fc_type, NULL); else return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -