diff options
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | modules/arabic/arabic-fc.c | 293 | ||||
-rw-r--r-- | modules/basic/basic-fc.c | 316 | ||||
-rw-r--r-- | modules/syriac/syriac-fc.c | 268 |
4 files changed, 196 insertions, 701 deletions
@@ -1,5 +1,25 @@ 2007-05-14 Behdad Esfahbod <behdad@gnome.org> + Part of Bug 325714 – Pango should respect $LANGUAGE + Bug 414264 – Pango vertical writing support is different with real + CJK usage. + + * modules/arabic/arabic-fc.c (arabic_engine_shape): + * modules/basic/basic-fc.c (basic_engine_shape): + * modules/syriac/syriac-fc.c (syriac_engine_shape): + Remove fallback_shape() paths. Remove get_ruleset(). + Use pango_ot_ruleset_get_for(), that correctly works for multiple + languages. Also makes basic shaper apply the 'vert' feature for + vertical text. Removes a net 500 lines. + + Other OpenType modules need to be ported over time, however some + extensions may be needed. For example, the Hebrew shaper uses + fallback code if no GPOS tables are available. Currently using + pango_ot_ruleset_get_for() one cannot see which features were + found. + +2007-05-14 Behdad Esfahbod <behdad@gnome.org> + Part of Bug 414264 – Pango vertical writing support is different with real CJK usage. diff --git a/modules/arabic/arabic-fc.c b/modules/arabic/arabic-fc.c index 2306bfe5..8b393fb8 100644 --- a/modules/arabic/arabic-fc.c +++ b/modules/arabic/arabic-fc.c @@ -49,199 +49,30 @@ static PangoEngineInfo script_engines[] = { } }; -static void -maybe_add_gsub_feature (PangoOTRuleset *ruleset, - PangoOTInfo *info, - guint script_index, - PangoOTTag tag, - gulong property_bit) -{ - guint feature_index; - - if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GSUB, - tag, script_index, PANGO_OT_DEFAULT_LANGUAGE, &feature_index)) - pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GSUB, feature_index, - property_bit); -} - -static void -maybe_add_gpos_feature (PangoOTRuleset *ruleset, - PangoOTInfo *info, - guint script_index, - PangoOTTag tag, - gulong property_bit) +static const PangoOTFeatureMap gsub_features[] = { - guint feature_index; - - if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GPOS, - tag, script_index, PANGO_OT_DEFAULT_LANGUAGE, &feature_index)) - pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GPOS, feature_index, - property_bit); -} - -static PangoOTRuleset * -get_ruleset (FT_Face face) -{ - PangoOTRuleset *ruleset; - static GQuark ruleset_quark = 0; - - PangoOTInfo *info = pango_ot_info_get (face); - - if (!ruleset_quark) - ruleset_quark = g_quark_from_string ("pango-arabic-ruleset"); - - if (!info) - return NULL; - - ruleset = g_object_get_qdata (G_OBJECT (info), ruleset_quark); - - if (!ruleset) - { - PangoOTTag arab_tag = FT_MAKE_TAG ('a', 'r', 'a', 'b'); - guint script_index; - - ruleset = pango_ot_ruleset_new (info); - - /* according to the Arabic OpenType spec, available here: - * http://www.microsoft.com/typography/otfntdev/arabicot/features.htm - */ - if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GSUB, - arab_tag, &script_index)) - { - /* Language based forms: */ - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('c','c','m','p'), PANGO_OT_ALL_GLYPHS); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('i','s','o','l'), isolated); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('f','i','n','a'), final); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','e','d','i'), medial); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('i','n','i','t'), initial); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('r','l','i','g'), PANGO_OT_ALL_GLYPHS); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('c','a','l','t'), PANGO_OT_ALL_GLYPHS); - - /* Typographical forms: */ - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('l','i','g','a'), PANGO_OT_ALL_GLYPHS); - /* this one should be turned-on/off-able. lets turn off for now. */ - /* maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('d','l','i','g'), PANGO_OT_ALL_GLYPHS); */ - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('c','s','w','h'), PANGO_OT_ALL_GLYPHS); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','s','e','t'), PANGO_OT_ALL_GLYPHS); - } - - if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GPOS, - arab_tag, &script_index)) - { - /* Positioning features: */ - maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('c','u','r','s'), PANGO_OT_ALL_GLYPHS); - maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('k','e','r','n'), PANGO_OT_ALL_GLYPHS); - maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','a','r','k'), PANGO_OT_ALL_GLYPHS); - maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','k','m','k'), PANGO_OT_ALL_GLYPHS); - } - - g_object_set_qdata_full (G_OBJECT (info), ruleset_quark, ruleset, - (GDestroyNotify)g_object_unref); - } - - return ruleset; -} - -static void -swap_range (PangoGlyphString *glyphs, int start, int end) -{ - int i, j; - - for (i = start, j = end - 1; i < j; i++, j--) - { - PangoGlyphInfo glyph_info; - gint log_cluster; - - glyph_info = glyphs->glyphs[i]; - glyphs->glyphs[i] = glyphs->glyphs[j]; - glyphs->glyphs[j] = glyph_info; - - log_cluster = glyphs->log_clusters[i]; - glyphs->log_clusters[i] = glyphs->log_clusters[j]; - glyphs->log_clusters[j] = log_cluster; - } -} - -static void -set_glyph (PangoFont *font, PangoGlyphString *glyphs, int i, int offset, PangoGlyph glyph) -{ - glyphs->glyphs[i].glyph = glyph; - glyphs->log_clusters[i] = offset; -} + {"ccmp", PANGO_OT_ALL_GLYPHS}, + {"locl", PANGO_OT_ALL_GLYPHS}, + {"isol", isolated}, + {"fina", final}, + {"medi", medial}, + {"init", initial}, + {"rlig", PANGO_OT_ALL_GLYPHS}, + {"calt", PANGO_OT_ALL_GLYPHS}, + {"liga", PANGO_OT_ALL_GLYPHS}, + /* 'dlig' should be turned-on/off-able. lets turn off for now. */ + /* {"dlig", PANGO_OT_ALL_GLYPHS}, */ + {"cswh", PANGO_OT_ALL_GLYPHS}, + {"mset", PANGO_OT_ALL_GLYPHS} +}; -static void -fallback_shape (PangoEngineShape *engine, - PangoFont *font, - const char *text, - gint length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs) +static const PangoOTFeatureMap gpos_features[] = { - PangoFcFont *fc_font = PANGO_FC_FONT (font); - glong n_chars = g_utf8_strlen (text, length); - const char *p; - int i; - - pango_glyph_string_set_size (glyphs, n_chars); - p = text; - - for (i=0; i < n_chars; i++) - { - gunichar wc; - gunichar mirrored_ch; - PangoGlyph index; - char buf[6]; - - wc = g_utf8_get_char (p); - - if (analysis->level % 2) - if (pango_get_mirror_char (wc, &mirrored_ch)) - { - wc = mirrored_ch; - - g_unichar_to_utf8 (wc, buf); - } - - if (pango_is_zero_width (wc)) - { - set_glyph (font, glyphs, i, p - text, PANGO_GLYPH_EMPTY); - } - else - { - index = pango_fc_font_get_glyph (fc_font, wc); - - if (!index) - index = PANGO_GET_UNKNOWN_GLYPH ( wc); - - set_glyph (font, glyphs, i, p - text, index); - } - - p = g_utf8_next_char (p); - } - - /* Apply default positioning */ - for (i = 0; i < glyphs->num_glyphs; i++) - { - if (glyphs->glyphs[i].glyph) - { - PangoRectangle logical_rect; - - pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect); - glyphs->glyphs[i].geometry.width = logical_rect.width; - } - else - glyphs->glyphs[i].geometry.width = 0; - - glyphs->glyphs[i].geometry.x_offset = 0; - glyphs->glyphs[i].geometry.y_offset = 0; - } - - if (analysis->level % 2 != 0) - { - /* Swap all glyphs */ - swap_range (glyphs, 0, glyphs->num_glyphs); - } -} + {"curs", PANGO_OT_ALL_GLYPHS}, + {"kern", PANGO_OT_ALL_GLYPHS}, + {"mark", PANGO_OT_ALL_GLYPHS}, + {"mkmk", PANGO_OT_ALL_GLYPHS} +}; static void arabic_engine_shape (PangoEngineShape *engine, @@ -253,7 +84,8 @@ arabic_engine_shape (PangoEngineShape *engine, { PangoFcFont *fc_font; FT_Face face; - PangoOTRuleset *ruleset; + PangoOTRulesetDescription desc; + const PangoOTRuleset *ruleset; PangoOTBuffer *buffer; gulong *properties = NULL; glong n_chars; @@ -272,12 +104,19 @@ arabic_engine_shape (PangoEngineShape *engine, if (!face) return; - ruleset = get_ruleset (face); - if (!ruleset) - { - fallback_shape (engine, font, text, length, analysis, glyphs); - goto out; - } + 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 (pango_ot_info_get (face), &desc); buffer = pango_ot_buffer_new (fc_font); pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0); @@ -294,64 +133,52 @@ arabic_engine_shape (PangoEngineShape *engine, for (i=0; i < n_chars; i++) { gunichar wc; - gunichar mirrored_ch; - PangoGlyph index; - char buf[6]; + PangoGlyph glyph; wc = g_utf8_get_char (p); - if (analysis->level % 2) - if (pango_get_mirror_char (wc, &mirrored_ch)) - { - wc = mirrored_ch; + if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) + cluster = p - text; - g_unichar_to_utf8 (wc, buf); - } - - if (pango_is_zero_width (wc)) /* Zero-width characters */ - { - pango_ot_buffer_add_glyph (buffer, PANGO_GLYPH_EMPTY, properties[i], p - text); - } + if (pango_is_zero_width (wc)) + glyph = PANGO_GLYPH_EMPTY; else - { + { + gunichar c = wc; + + if (analysis->level % 2) + g_unichar_get_mirror_char (c, &c); + /* Hack - Microsoft fonts are strange and don't contain the * correct rules to shape ARABIC LETTER FARSI YEH in * medial/initial position. It looks identical to ARABIC LETTER * YEH in these positions, so we substitute if the font contains * ARABIC LETTER YEH */ - if (wc == 0x6cc && ruleset && pango_fc_font_get_glyph (fc_font, 0x64a) && - ((properties[i] & (initial | medial)) != (initial | medial))) - wc = 0x64a; - - index = pango_fc_font_get_glyph (fc_font, wc); - - if (!index) - { - pango_ot_buffer_add_glyph (buffer, PANGO_GET_UNKNOWN_GLYPH ( wc), - properties[i], p - text); - } - else - { - if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) - cluster = p - text; - - pango_ot_buffer_add_glyph (buffer, index, - properties[i], cluster); - } + if (c == 0x6cc && + ((properties[i] & (initial | medial)) != (initial | medial)) && + pango_fc_font_has_char (fc_font, 0x64a)) + c = 0x64a; + + glyph = pango_fc_font_get_glyph (fc_font, c); } + if (!glyph) + glyph = PANGO_GET_UNKNOWN_GLYPH (wc); + + pango_ot_buffer_add_glyph (buffer, glyph, properties[i], cluster); + p = g_utf8_next_char (p); } + g_free (properties); + pango_ot_ruleset_substitute (ruleset, buffer); pango_ot_ruleset_position (ruleset, buffer); pango_ot_buffer_output (buffer, glyphs); - g_free (properties); pango_ot_buffer_destroy (buffer); - out: pango_fc_font_unlock_face (fc_font); } diff --git a/modules/basic/basic-fc.c b/modules/basic/basic-fc.c index 300dd1f8..f576af1c 100644 --- a/modules/basic/basic-fc.c +++ b/modules/basic/basic-fc.c @@ -39,23 +39,27 @@ typedef PangoEngineShapeClass BasicEngineFcClass; #define RENDER_TYPE PANGO_RENDER_TYPE_FC static PangoEngineScriptInfo basic_scripts[] = { + /* Listed in OpenType "Standard scripts" standard */ + { PANGO_SCRIPT_LATIN, "*" }, + { PANGO_SCRIPT_CYRILLIC, "*" }, + { PANGO_SCRIPT_GREEK, "*" }, { PANGO_SCRIPT_ARMENIAN, "*" }, + { PANGO_SCRIPT_GEORGIAN, "*" }, + { PANGO_SCRIPT_RUNIC, "*" }, + { PANGO_SCRIPT_OGHAM, "*" }, + + /* The following are simple and can be shaped easily too */ + { PANGO_SCRIPT_BOPOMOFO, "*" }, { PANGO_SCRIPT_CHEROKEE, "*" }, { PANGO_SCRIPT_COPTIC, "*" }, - { PANGO_SCRIPT_CYRILLIC, "*" }, { PANGO_SCRIPT_DESERET, "*" }, { PANGO_SCRIPT_ETHIOPIC, "*" }, - { PANGO_SCRIPT_GEORGIAN, "*" }, { PANGO_SCRIPT_GOTHIC, "*" }, - { PANGO_SCRIPT_GREEK, "*" }, { PANGO_SCRIPT_HAN, "*" }, { PANGO_SCRIPT_HIRAGANA, "*" }, { PANGO_SCRIPT_KATAKANA, "*" }, - { PANGO_SCRIPT_LATIN, "*" }, - { PANGO_SCRIPT_OGHAM, "*" }, { PANGO_SCRIPT_OLD_ITALIC, "*" }, - { PANGO_SCRIPT_RUNIC, "*" }, { PANGO_SCRIPT_CANADIAN_ABORIGINAL, "*" }, { PANGO_SCRIPT_YI, "*" }, @@ -75,6 +79,7 @@ static PangoEngineScriptInfo basic_scripts[] = { { PANGO_SCRIPT_CUNEIFORM, "*" }, { PANGO_SCRIPT_PHOENICIAN, "*" }, + /* In fact any script we don't know how to shape can go here */ { PANGO_SCRIPT_COMMON, "" } }; @@ -87,220 +92,28 @@ static PangoEngineInfo script_engines[] = { } }; -static void -swap_range (PangoGlyphString *glyphs, - int start, - int end) -{ - int i, j; - - for (i = start, j = end - 1; i < j; i++, j--) - { - PangoGlyphInfo glyph_info; - gint log_cluster; - - glyph_info = glyphs->glyphs[i]; - glyphs->glyphs[i] = glyphs->glyphs[j]; - glyphs->glyphs[j] = glyph_info; - - log_cluster = glyphs->log_clusters[i]; - glyphs->log_clusters[i] = glyphs->log_clusters[j]; - glyphs->log_clusters[j] = log_cluster; - } -} - -static void -set_glyph (PangoFont *font, - PangoGlyphString *glyphs, - int i, - int offset, - PangoGlyph glyph) -{ - PangoRectangle logical_rect; - - glyphs->glyphs[i].glyph = glyph; - - glyphs->glyphs[i].geometry.x_offset = 0; - glyphs->glyphs[i].geometry.y_offset = 0; - - glyphs->log_clusters[i] = offset; - - pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect); - glyphs->glyphs[i].geometry.width = logical_rect.width; -} - -static void -fallback_shape (PangoEngineShape *engine, - PangoFont *font, - const char *text, - gint length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs) -{ - PangoFcFont *fc_font = PANGO_FC_FONT (font); - glong n_chars = g_utf8_strlen (text, length); - const char *p; - int i; - - pango_glyph_string_set_size (glyphs, n_chars); - p = text; - - for (i=0; i < n_chars; i++) - { - gunichar wc; - gunichar mirrored_ch; - PangoGlyph index; - char buf[6]; - - wc = g_utf8_get_char (p); - - if (analysis->level % 2) - if (pango_get_mirror_char (wc, &mirrored_ch)) - { - wc = mirrored_ch; - - g_unichar_to_utf8 (wc, buf); - } - - if (wc == 0xa0) /* non-break-space */ - wc = 0x20; - - if (pango_is_zero_width (wc)) - { - set_glyph (font, glyphs, i, p - text, PANGO_GLYPH_EMPTY); - } - else - { - index = pango_fc_font_get_glyph (fc_font, wc); - - if (!index) - { - index = PANGO_GET_UNKNOWN_GLYPH ( wc); - set_glyph (font, glyphs, i, p - text, index); - } - else - { - set_glyph (font, glyphs, i, p - text, index); - - if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK) - { - if (i > 0) - { - PangoRectangle logical_rect, ink_rect; - - glyphs->glyphs[i].geometry.width = MAX (glyphs->glyphs[i-1].geometry.width, - glyphs->glyphs[i].geometry.width); - glyphs->glyphs[i-1].geometry.width = 0; - glyphs->log_clusters[i] = glyphs->log_clusters[i-1]; - - /* Some heuristics to try to guess how overstrike glyphs are - * done and compensate - */ - pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, &ink_rect, &logical_rect); - if (logical_rect.width == 0 && ink_rect.x == 0) - glyphs->glyphs[i].geometry.x_offset = (glyphs->glyphs[i].geometry.width - ink_rect.width) / 2; - } - } - } - } - - p = g_utf8_next_char (p); - } - - if (analysis->level % 2 != 0) - { - /* Swap all glyphs */ - swap_range (glyphs, 0, glyphs->num_glyphs); - } -} - -static const gchar scripts[][5] = +static const PangoOTFeatureMap gsub_features[] = { - "latn", - "cyrl", - "grek", - "armn", - "geor", - "runr", - "ogam" + {"ccmp", PANGO_OT_ALL_GLYPHS}, + {"locl", PANGO_OT_ALL_GLYPHS}, + {"liga", PANGO_OT_ALL_GLYPHS}, + {"clig", PANGO_OT_ALL_GLYPHS} }; -static const gchar gsub_features[][5] = +static const PangoOTFeatureMap gpos_features[] = { - "ccmp", - "liga", - "clig", + {"kern", PANGO_OT_ALL_GLYPHS}, + {"mark", PANGO_OT_ALL_GLYPHS}, + {"mkmk", PANGO_OT_ALL_GLYPHS} }; -static const gchar gpos_features[][5] = +static const PangoOTFeatureMap vertical_gsub_features[] = { - "kern", - "mark", - "mkmk" + {"ccmp", PANGO_OT_ALL_GLYPHS}, + {"locl", PANGO_OT_ALL_GLYPHS}, + {"vert", PANGO_OT_ALL_GLYPHS} }; -static PangoOTRuleset * -get_ruleset (FT_Face face) -{ - PangoOTRuleset *ruleset; - PangoOTInfo *info = NULL; - static GQuark ruleset_quark = 0; - unsigned int i, j; - - info = pango_ot_info_get (face); - if (!info) - return NULL; - - if (!ruleset_quark) - ruleset_quark = g_quark_from_string ("pango-basic-ruleset"); - - ruleset = g_object_get_qdata (G_OBJECT (info), ruleset_quark); - - if (!ruleset) - { - ruleset = pango_ot_ruleset_new (info); - - for (i = 0; i < G_N_ELEMENTS (scripts); i++) - { - PangoOTTag script_tag = FT_MAKE_TAG (scripts[i][0], scripts[i][1], scripts[i][2], scripts[i][3]); - guint script_index; - - - if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GPOS, script_tag, &script_index)) - for (j = 0; j < G_N_ELEMENTS (gpos_features); j++) - { - PangoOTTag feature_tag = FT_MAKE_TAG (gpos_features[j][0], gpos_features[j][1], - gpos_features[j][2], gpos_features[j][3]); - guint feature_index; - - if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GPOS, feature_tag, script_index, PANGO_OT_DEFAULT_LANGUAGE ,&feature_index)) - { - pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GPOS, feature_index, PANGO_OT_ALL_GLYPHS); - } - } - - if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GSUB, script_tag, &script_index)) - for (j = 0; j < G_N_ELEMENTS (gsub_features); j++) - { - PangoOTTag feature_tag = FT_MAKE_TAG (gsub_features[j][0], gsub_features[j][1], - gsub_features[j][2], gsub_features[j][3]); - guint feature_index; - - if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GSUB, feature_tag, - script_index, PANGO_OT_DEFAULT_LANGUAGE, &feature_index)) - { - pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GSUB, feature_index, PANGO_OT_ALL_GLYPHS); - } - } - } - - g_object_set_qdata_full (G_OBJECT (info), ruleset_quark, ruleset, (GDestroyNotify) g_object_unref); - } - - return ruleset; - -} - static void basic_engine_shape (PangoEngineShape *engine, PangoFont *font, @@ -311,14 +124,13 @@ basic_engine_shape (PangoEngineShape *engine, { PangoFcFont *fc_font; FT_Face face; - PangoOTRuleset *ruleset; + PangoOTRulesetDescription desc; + const PangoOTRuleset *ruleset; PangoOTBuffer *buffer; - gint unknown_property = 0; glong n_chars; const char *p; int cluster = 0; int i; - gboolean vertical; g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); @@ -330,21 +142,30 @@ basic_engine_shape (PangoEngineShape *engine, if (!face) return; - vertical = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity); - if (vertical) + desc.script = analysis->script; + desc.language = analysis->language; + + if (PANGO_GRAVITY_IS_VERTICAL (analysis->gravity)) { - fallback_shape (engine, font, text, length, analysis, glyphs); - goto out; + desc.n_static_gsub_features = G_N_ELEMENTS (vertical_gsub_features); + desc.static_gsub_features = vertical_gsub_features; + desc.n_static_gpos_features = 0; + desc.static_gpos_features = NULL; } - - ruleset = get_ruleset (face); - if (!ruleset) + else { - fallback_shape (engine, font, text, length, analysis, glyphs); - pango_fc_font_kern_glyphs (fc_font, glyphs); - goto out; + 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 (pango_ot_info_get (face), &desc); + buffer = pango_ot_buffer_new (fc_font); pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0); @@ -355,42 +176,30 @@ basic_engine_shape (PangoEngineShape *engine, for (i=0; i < n_chars; i++) { gunichar wc; - gunichar mirrored_ch; - PangoGlyph index; - char buf[6]; + PangoGlyph glyph; wc = g_utf8_get_char (p); - if (analysis->level % 2) - if (pango_get_mirror_char (wc, &mirrored_ch)) - { - wc = mirrored_ch; - g_unichar_to_utf8 (wc, buf); - } + if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) + cluster = p - text; - if (pango_is_zero_width (wc)) /* Zero-width characters */ - { - pango_ot_buffer_add_glyph (buffer, PANGO_GLYPH_EMPTY, unknown_property, p - text); - } + if (pango_is_zero_width (wc)) + glyph = PANGO_GLYPH_EMPTY; else - { - index = pango_fc_font_get_glyph (fc_font, wc); - - if (!index) - { - pango_ot_buffer_add_glyph (buffer, PANGO_GET_UNKNOWN_GLYPH ( wc), - unknown_property, p - text); - } - else - { - if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) - cluster = p - text; - - pango_ot_buffer_add_glyph (buffer, index, - unknown_property, cluster); - } + { + gunichar c = wc; + + if (analysis->level % 2) + g_unichar_get_mirror_char (c, &c); + + glyph = pango_fc_font_get_glyph (fc_font, c); } + if (!glyph) + glyph = PANGO_GET_UNKNOWN_GLYPH (wc); + + pango_ot_buffer_add_glyph (buffer, glyph, 0, cluster); + p = g_utf8_next_char (p); } @@ -401,7 +210,6 @@ basic_engine_shape (PangoEngineShape *engine, pango_ot_buffer_destroy (buffer); -out: pango_fc_font_unlock_face (fc_font); } diff --git a/modules/syriac/syriac-fc.c b/modules/syriac/syriac-fc.c index 3065ceba..b024cb14 100644 --- a/modules/syriac/syriac-fc.c +++ b/modules/syriac/syriac-fc.c @@ -51,190 +51,30 @@ static PangoEngineInfo script_engines[] = { } }; -static void -maybe_add_gsub_feature (PangoOTRuleset *ruleset, - PangoOTInfo *info, - guint script_index, - PangoOTTag tag, - gulong property_bit) -{ - guint feature_index; - - if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GSUB, - tag, script_index, PANGO_OT_DEFAULT_LANGUAGE, &feature_index)) - pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GSUB, feature_index, - property_bit); -} - -static void -maybe_add_gpos_feature (PangoOTRuleset *ruleset, - PangoOTInfo *info, - guint script_index, - PangoOTTag tag, - gulong property_bit) +static const PangoOTFeatureMap gsub_features[] = { - guint feature_index; - - if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GPOS, - tag, script_index, PANGO_OT_DEFAULT_LANGUAGE, &feature_index)) - pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GPOS, feature_index, - property_bit); -} - -static PangoOTRuleset * -get_ruleset (FT_Face face) -{ - PangoOTRuleset *ruleset; - static GQuark ruleset_quark = 0; - - PangoOTInfo *info = pango_ot_info_get (face); - - if (!ruleset_quark) - ruleset_quark = g_quark_from_string ("pango-syriac-ruleset"); - - if (!info) - return NULL; - - ruleset = g_object_get_qdata (G_OBJECT (info), ruleset_quark); - - if (!ruleset) - { - PangoOTTag syrc_tag = FT_MAKE_TAG ('s', 'y', 'r', 'c'); - guint script_index; - - ruleset = pango_ot_ruleset_new (info); - - if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GSUB, - syrc_tag, &script_index)) - { - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('c','c','m','p'), PANGO_OT_ALL_GLYPHS); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('i','s','o','l'), isolated); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('f','i','n','a'), final); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('f','i','n','2'), final2); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('f','i','n','3'), final3); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','e','d','i'), medial); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','e','d','2'), medial2); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('i','n','i','t'), initial); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('r','l','i','g'), PANGO_OT_ALL_GLYPHS); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('c','a','l','t'), PANGO_OT_ALL_GLYPHS); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('l','i','g','a'), PANGO_OT_ALL_GLYPHS); - maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('d','l','i','g'), PANGO_OT_ALL_GLYPHS); - } - - if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GPOS, - syrc_tag, &script_index)) - { - maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('k','e','r','n'), PANGO_OT_ALL_GLYPHS); - maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','a','r','k'), PANGO_OT_ALL_GLYPHS); - maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','k','m','k'), PANGO_OT_ALL_GLYPHS); - } - - g_object_set_qdata_full (G_OBJECT (info), ruleset_quark, ruleset, - (GDestroyNotify)g_object_unref); - } - - return ruleset; -} - -static void -swap_range (PangoGlyphString *glyphs, int start, int end) -{ - int i, j; - - for (i = start, j = end - 1; i < j; i++, j--) - { - PangoGlyphInfo glyph_info; - gint log_cluster; - - glyph_info = glyphs->glyphs[i]; - glyphs->glyphs[i] = glyphs->glyphs[j]; - glyphs->glyphs[j] = glyph_info; - - log_cluster = glyphs->log_clusters[i]; - glyphs->log_clusters[i] = glyphs->log_clusters[j]; - glyphs->log_clusters[j] = log_cluster; - } -} - -static void -set_glyph (PangoFont *font, - PangoGlyphString *glyphs, - int i, - int offset, - PangoGlyph glyph) -{ - glyphs->glyphs[i].glyph = glyph; - glyphs->log_clusters[i] = offset; -} + {"ccmp", PANGO_OT_ALL_GLYPHS}, + {"locl", PANGO_OT_ALL_GLYPHS}, + {"isol", isolated}, + {"fina", final}, + {"fin2", final2}, + {"fin3", final3}, + {"medi", medial}, + {"med2", medial2}, + {"init", initial}, + {"rlig", PANGO_OT_ALL_GLYPHS}, + {"calt", PANGO_OT_ALL_GLYPHS}, + {"liga", PANGO_OT_ALL_GLYPHS}, + /* 'dlig' should be turned-on/off-able. lets turn off for now. */ + /* {"dlig", PANGO_OT_ALL_GLYPHS}, */ +}; -static void -fallback_shape (PangoEngineShape *engine, - PangoFont *font, - const char *text, - gint length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs) +static const PangoOTFeatureMap gpos_features[] = { - PangoFcFont *fc_font = PANGO_FC_FONT (font); - glong n_chars = g_utf8_strlen (text, length); - const char *p; - int i; - - pango_glyph_string_set_size (glyphs, n_chars); - p = text; - - for (i=0; i < n_chars; i++) - { - gunichar wc; - gunichar mirrored_ch; - PangoGlyph index; - - wc = g_utf8_get_char (p); - - if ((analysis->level % 2) && - pango_get_mirror_char (wc, &mirrored_ch)) - wc = mirrored_ch; - - if (pango_is_zero_width (wc)) - { - set_glyph (font, glyphs, i, p - text, PANGO_GLYPH_EMPTY); - } - else - { - index = pango_fc_font_get_glyph (fc_font, wc); - - if (!index) - index = PANGO_GET_UNKNOWN_GLYPH ( wc); - - set_glyph (font, glyphs, i, p - text, index); - } - - p = g_utf8_next_char (p); - } - - /* Apply default positioning */ - for (i = 0; i < glyphs->num_glyphs; i++) - { - if (glyphs->glyphs[i].glyph) - { - PangoRectangle logical_rect; - - pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect); - glyphs->glyphs[i].geometry.width = logical_rect.width; - } - else - glyphs->glyphs[i].geometry.width = 0; - - glyphs->glyphs[i].geometry.x_offset = 0; - glyphs->glyphs[i].geometry.y_offset = 0; - } - - if (analysis->level % 2 != 0) - { - /* Swap all glyphs */ - swap_range (glyphs, 0, glyphs->num_glyphs); - } -} + {"kern", PANGO_OT_ALL_GLYPHS}, + {"mark", PANGO_OT_ALL_GLYPHS}, + {"mkmk", PANGO_OT_ALL_GLYPHS} +}; static void syriac_engine_shape (PangoEngineShape *engine, @@ -246,7 +86,8 @@ syriac_engine_shape (PangoEngineShape *engine, { PangoFcFont *fc_font; FT_Face face; - PangoOTRuleset *ruleset; + PangoOTRulesetDescription desc; + const PangoOTRuleset *ruleset; PangoOTBuffer *buffer; gulong *properties = NULL; glong n_chars; @@ -265,12 +106,19 @@ syriac_engine_shape (PangoEngineShape *engine, if (!face) return; - ruleset = get_ruleset (face); - if (!ruleset) - { - fallback_shape (engine, font, text, length, analysis, glyphs); - goto out; - } + 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 (pango_ot_info_get (face), &desc); buffer = pango_ot_buffer_new (fc_font); pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0); @@ -287,49 +135,41 @@ syriac_engine_shape (PangoEngineShape *engine, for (i=0; i < n_chars; i++) { gunichar wc; - gunichar mirrored_ch; - PangoGlyph index; + PangoGlyph glyph; wc = g_utf8_get_char (p); - if ((analysis->level % 2) && - pango_get_mirror_char (wc, &mirrored_ch)) - wc = mirrored_ch; + if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) + cluster = p - text; if (pango_is_zero_width (wc)) - { - pango_ot_buffer_add_glyph (buffer, PANGO_GLYPH_EMPTY, properties[i], p - text); - } + glyph = PANGO_GLYPH_EMPTY; else - { - index = pango_fc_font_get_glyph (fc_font, wc); - - if (!index) - { - pango_ot_buffer_add_glyph (buffer, PANGO_GET_UNKNOWN_GLYPH ( wc), - properties[i], p - text); - } - else - { - if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) - cluster = p - text; - - pango_ot_buffer_add_glyph (buffer, index, - properties[i], cluster); - } + { + gunichar c = wc; + + if (analysis->level % 2) + g_unichar_get_mirror_char (c, &c); + + glyph = pango_fc_font_get_glyph (fc_font, c); } + if (!glyph) + glyph = PANGO_GET_UNKNOWN_GLYPH (wc); + + pango_ot_buffer_add_glyph (buffer, glyph, properties[i], cluster); + p = g_utf8_next_char (p); } + g_free (properties); + pango_ot_ruleset_substitute (ruleset, buffer); pango_ot_ruleset_position (ruleset, buffer); pango_ot_buffer_output (buffer, glyphs); - g_free (properties); pango_ot_buffer_destroy (buffer); - out: pango_fc_font_unlock_face (fc_font); } |