From f4bbca78a0c8acc3ce6792532ca1f86663b68d71 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Mon, 22 Nov 2004 20:31:11 +0000 Subject: Add Syriac module by Emil Soleyman-Zomalan. (#147779) Mon Nov 22 15:21:11 2004 Owen Taylor * modules/syriac configure.in modules/Makefile.am modules/makefile.msc: Add Syriac module by Emil Soleyman-Zomalan. (#147779) * examples/Makefile.am examples/syriac.utf: Syriac example text. --- ChangeLog | 9 ++ ChangeLog.pre-1-10 | 9 ++ ChangeLog.pre-1-8 | 9 ++ configure.in | 6 +- examples/Makefile.am | 1 + examples/syriac.utf | 18 +++ modules/Makefile.am | 3 +- modules/makefile.msc | 6 +- modules/syriac/.cvsignore | 6 + modules/syriac/Makefile.am | 46 ++++++ modules/syriac/syriac-fc.c | 372 +++++++++++++++++++++++++++++++++++++++++++++ modules/syriac/syriac-ot.c | 362 +++++++++++++++++++++++++++++++++++++++++++ modules/syriac/syriac-ot.h | 69 +++++++++ 13 files changed, 913 insertions(+), 3 deletions(-) create mode 100644 examples/syriac.utf create mode 100644 modules/syriac/.cvsignore create mode 100644 modules/syriac/Makefile.am create mode 100644 modules/syriac/syriac-fc.c create mode 100644 modules/syriac/syriac-ot.c create mode 100644 modules/syriac/syriac-ot.h diff --git a/ChangeLog b/ChangeLog index e1e56999..a7590b1b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Mon Nov 22 15:21:11 2004 Owen Taylor + + * modules/syriac configure.in modules/Makefile.am + modules/makefile.msc: Add Syriac module by Emil + Soleyman-Zomalan. (#147779) + + * examples/Makefile.am examples/syriac.utf: Syriac + example text. + 2004-11-21 Hans Breuer * pango/makefile.msc : updated diff --git a/ChangeLog.pre-1-10 b/ChangeLog.pre-1-10 index e1e56999..a7590b1b 100644 --- a/ChangeLog.pre-1-10 +++ b/ChangeLog.pre-1-10 @@ -1,3 +1,12 @@ +Mon Nov 22 15:21:11 2004 Owen Taylor + + * modules/syriac configure.in modules/Makefile.am + modules/makefile.msc: Add Syriac module by Emil + Soleyman-Zomalan. (#147779) + + * examples/Makefile.am examples/syriac.utf: Syriac + example text. + 2004-11-21 Hans Breuer * pango/makefile.msc : updated diff --git a/ChangeLog.pre-1-8 b/ChangeLog.pre-1-8 index e1e56999..a7590b1b 100644 --- a/ChangeLog.pre-1-8 +++ b/ChangeLog.pre-1-8 @@ -1,3 +1,12 @@ +Mon Nov 22 15:21:11 2004 Owen Taylor + + * modules/syriac configure.in modules/Makefile.am + modules/makefile.msc: Add Syriac module by Emil + Soleyman-Zomalan. (#147779) + + * examples/Makefile.am examples/syriac.utf: Syriac + example text. + 2004-11-21 Hans Breuer * pango/makefile.msc : updated diff --git a/configure.in b/configure.in index 5e5f6a34..2756140d 100644 --- a/configure.in +++ b/configure.in @@ -348,8 +348,9 @@ hangul_modules="hangul-fc" hebrew_modules="hebrew-fc" indic_modules="indic-fc" thai_modules="thai-fc" +syriac_modules="syriac-fc" -all_modules="$arabic_modules,$basic_modules,$hangul_modules,$hebrew_modules,$indic_modules,$thai_modules" +all_modules="$arabic_modules,$basic_modules,$hangul_modules,$hebrew_modules,$indic_modules,$thai_modules,$syriac_modules" included_modules="" if test "x$with_included_modules" != xno || test "x$with_included_modules" = x ; then @@ -406,6 +407,8 @@ AM_CONDITIONAL(INCLUDE_THAI_FC,echo $included_modules | egrep '(^|,)thai-fc($|,) AM_CONDITIONAL(INCLUDE_INDIC_FC,echo $included_modules | egrep '(^|,)indic-fc($|,)' > /dev/null) +AM_CONDITIONAL(INCLUDE_SYRIAC_FC,echo $included_modules | egrep '(^|,)syriac-fc($|,)' > /dev/null) + # # We use flockfile to implement pango_getline() - should be moved to GLib # strtok_r isn't present on some systems @@ -662,6 +665,7 @@ modules/hangul/Makefile modules/indic/Makefile modules/thai/Makefile modules/hebrew/Makefile +modules/syriac/Makefile examples/Makefile docs/Makefile docs/version.xml diff --git a/examples/Makefile.am b/examples/Makefile.am index 2286cc71..91ca4b02 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -74,6 +74,7 @@ EXTRA_DIST= \ HELLO.utf8 \ dev-example.utf \ muru.utf \ + syriac.utf \ pangorc \ pangox.aliases diff --git a/examples/syriac.utf b/examples/syriac.utf new file mode 100644 index 00000000..05fedc7b --- /dev/null +++ b/examples/syriac.utf @@ -0,0 +1,18 @@ +ܠܫܢܢ +ܒܝܕܦܪܝܕܐ ܒܢܝܡܝܢ ܐܕܡ + +ܐܬܐܡܘܢ ܥܠܝܡܢ ܘܥܠܝܡܬܢ +ܠܫܢܢ ܡܪܢܝܐ +ܦܪܝܣܐ ܡܕܘܪܐ ܩܕܡܝܐ + +ܠܫܢܢ ܝܠܗ ܐܝܬܘܬܢ +ܘܬܘܕܝܬܢ ܘܣܦܪܝܘܬܢ +ܝܠܦܚܠܗ ܒܟܠ ܫܘܒ݂ܗܪܐ + +ܡܒܘܥܐ ܗܘܐ ܕܝܘܠܦܢܐ +ܚܠܝܐ ܒܪܬܡܐ ܘܩܪܝܢܐ +ܬܓ݂ܐ ܝܠܗ ܠܪܫܢ ܪܡܐ + +ܡܠܦܢܢ ܐܢܝ ܓܢܒܪܐ +ܡܫܘܬܐܣܠܗܘܢ ܡܕܪܫܝܬܐ +ܡܫܘܬܐܣܠܗܘܢ ܓܘ ܐܡܘܬܐ diff --git a/modules/Makefile.am b/modules/Makefile.am index b4954443..8b67df8b 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -6,7 +6,8 @@ SUBDIRS = \ hangul \ indic \ thai \ - hebrew + hebrew \ + syriac EXTRA_DIST = \ module.def diff --git a/modules/makefile.msc b/modules/makefile.msc index eef35ba9..e56edf6a 100644 --- a/modules/makefile.msc +++ b/modules/makefile.msc @@ -1,6 +1,6 @@ # modles for the ft2 backend, don't include 'basic' # here it is built-in pangoft.dll, see ../pango/makefile.msc -MODULES = arabic hangul hebrew indic thai +MODULES = arabic hangul hebrew indic syriac thai !IFNDEF MODULE @@ -35,6 +35,10 @@ OBJECTS = hebrew-fc.obj hebrew-shaper.obj OBJECTS = indic-fc.obj indic-ot.obj indic-ot-class-tables.obj mprefixups.obj !ENDIF +!IFDEF OBJ_syriac +OBJECTS = syriac-fc.obj syriac-ot.obj +!ENDIF + !IFDEF OBJ_thai OBJECTS = thai-fc.obj thai-shaper.obj !ENDIF diff --git a/modules/syriac/.cvsignore b/modules/syriac/.cvsignore new file mode 100644 index 00000000..6e5ca7ed --- /dev/null +++ b/modules/syriac/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +.deps +.libs +*.lo +*.la diff --git a/modules/syriac/Makefile.am b/modules/syriac/Makefile.am new file mode 100644 index 00000000..2f0630e1 --- /dev/null +++ b/modules/syriac/Makefile.am @@ -0,0 +1,46 @@ +## Process this file with automake to create Makefile.in. + +pangolibs = $(top_builddir)/pango/libpango-$(PANGO_API_VERSION).la $(GLIB_LIBS) +pangoft2libs = $(top_builddir)/pango/libpangoft2-$(PANGO_API_VERSION).la $(FREETYPE_LIBS) $(pangolibs) + +INCLUDES = \ + -DPANGO_ENABLE_ENGINE \ + -DG_DISABLE_DEPRECATED \ + $(PANGO_DEBUG_FLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/pango/ \ + $(GLIB_CFLAGS) + +moduledir = $(libdir)/pango/$(PANGO_MODULE_VERSION)/modules +module_LTLIBRARIES = +noinst_LTLIBRARIES = + +if PLATFORM_WIN32 +no_undefined = -no-undefined +endif + + +if HAVE_FREETYPE +INCLUDES += $(FREETYPE_CFLAGS) +if INCLUDE_SYRIAC_FC +noinst_LTLIBRARIES += libpango-syriac-fc.la +else +module_LTLIBRARIES += pango-syriac-fc.la +endif +endif + +fc_sources = \ + syriac-fc.c \ + syriac-ot.c \ + syriac-ot.h + +pango_syriac_fc_la_LDFLAGS = -export-dynamic -avoid-version -module $(no_undefined) +pango_syriac_fc_la_LIBADD = $(pangoft2libs) +pango_syriac_fc_la_SOURCES = $(fc_sources) +libpango_syriac_fc_la_SOURCES = $(fc_sources) +libpango_syriac_fc_la_CFLAGS = -DPANGO_MODULE_PREFIX=_pango_syriac_fc + + +included-modules: $(noinst_LTLIBRARIES) + +.PHONY: included-modules diff --git a/modules/syriac/syriac-fc.c b/modules/syriac/syriac-fc.c new file mode 100644 index 00000000..59d5bfb7 --- /dev/null +++ b/modules/syriac/syriac-fc.c @@ -0,0 +1,372 @@ +/* Pango + * syriac-fc.h: + * + * Copyright (C) 2000, 2003 Red Hat Software + * Author: Owen Taylor + * + * Copyright (C) 2004 Emil Soleyman-Zomalan + * Author: Emil Soleyman-Zomalan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "syriac-ot.h" + +#include "pango-engine.h" +#include "pango-utils.h" +#include "pangofc-font.h" + +/* No extra fields needed */ +typedef PangoEngineShape SyriacEngineFc; +typedef PangoEngineShapeClass SyriacEngineFcClass ; + +#define SCRIPT_ENGINE_NAME "SyriacScriptEngineFc" +#define RENDER_TYPE PANGO_RENDER_TYPE_FC + +static PangoEngineScriptInfo syriac_scripts[] = { + { PANGO_SCRIPT_SYRIAC, "*" }, +}; + +static PangoEngineInfo script_engines[] = { + { + SCRIPT_ENGINE_NAME, + PANGO_ENGINE_TYPE_SHAPE, + RENDER_TYPE, + syriac_scripts, G_N_ELEMENTS(syriac_scripts) + } +}; + +static void +maybe_add_gsub_feature (PangoOTRuleset *ruleset, + PangoOTInfo *info, + guint script_index, + PangoOTTag tag, + gulong property_bit) +{ + guint feature_index; + + /* 0xffff == default language system */ + if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GSUB, + tag, script_index, 0xffff, &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) +{ + guint feature_index; + + /* 0xffff == default language system */ + if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GPOS, + tag, script_index, 0xffff, &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); + +#define ALL_GLYPHS ~(gulong)0 + + 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'), 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'), ALL_GLYPHS); + maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('c','a','l','t'), ALL_GLYPHS); + maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('l','i','g','a'), ALL_GLYPHS); + maybe_add_gsub_feature (ruleset, info, script_index, FT_MAKE_TAG ('d','l','i','g'), 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'), ALL_GLYPHS); + maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','a','r','k'), ALL_GLYPHS); + maybe_add_gpos_feature (ruleset, info, script_index, FT_MAKE_TAG ('m','k','m','k'), 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; +} + +static void +fallback_shape (PangoEngineShape *engine, + PangoFont *font, + const char *text, + gint length, + PangoAnalysis *analysis, + PangoGlyphString *glyphs) +{ + PangoFcFont *fc_font = PANGO_FC_FONT (font); + glong n_chars; + gunichar *wcs = g_utf8_to_ucs4_fast (text, length, &n_chars); + 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 (wc >= 0x200B && wc <= 0x200F) /* Zero-width characters */ + { + set_glyph (font, glyphs, i, p - text, 0); + } + else + { + index = pango_fc_font_get_glyph (fc_font, wc); + + if (!index) + index = pango_fc_font_get_unknown_glyph (fc_font, 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); + } + + g_free (wcs); +} + +static void +syriac_engine_shape (PangoEngineShape *engine, + PangoFont *font, + const char *text, + gint length, + PangoAnalysis *analysis, + PangoGlyphString *glyphs) +{ + glong n_chars; + gunichar *wcs; + int i; + const char *p; + gulong *properties = NULL; + FT_Face face; + PangoOTRuleset *ruleset; + PangoOTBuffer *buffer; + PangoFcFont *fc_font; + + 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); + g_assert (face); + + ruleset = get_ruleset (face); + if (!ruleset) + { + fallback_shape (engine, font, text, length, analysis, glyphs); + goto out; + } + + buffer = pango_ot_buffer_new (fc_font); + pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0); + + wcs = g_utf8_to_ucs4_fast (text, length, &n_chars); + properties = g_new0 (gulong, n_chars); + + syriac_assign_properties (wcs, properties, n_chars); + + p = text; + for (i=0; i < n_chars; i++) + { + gunichar wc; + gunichar mirrored_ch; + PangoGlyph index; + int cluster = 0; + + wc = g_utf8_get_char (p); + + if ((analysis->level % 2) && + pango_get_mirror_char (wc, &mirrored_ch)) + wc = mirrored_ch; + + if (wc >= 0x200B && wc <= 0x200F) /* Zero-width characters */ + { + pango_ot_buffer_add_glyph (buffer, 0, properties[i], p - text); + } + else + { + index = pango_fc_font_get_glyph (fc_font, wc); + + if (!index) + { + pango_ot_buffer_add_glyph (buffer, pango_fc_font_get_unknown_glyph (fc_font, 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); + } + } + + p = g_utf8_next_char (p); + } + + pango_ot_ruleset_substitute (ruleset, buffer); + pango_ot_ruleset_position (ruleset, buffer); + pango_ot_buffer_output (buffer, glyphs); + + g_free (wcs); + g_free (properties); + pango_ot_buffer_destroy (buffer); + + out: + pango_fc_font_unlock_face (fc_font); +} + +static void +syriac_engine_fc_class_init (PangoEngineShapeClass *class) +{ + class->script_shape = syriac_engine_shape; +} + +PANGO_ENGINE_SHAPE_DEFINE_TYPE (SyriacEngineFc, syriac_engine_fc, + syriac_engine_fc_class_init, NULL); + +void +PANGO_MODULE_ENTRY(init) (GTypeModule *module) +{ + syriac_engine_fc_register_type (module); +} + +void +PANGO_MODULE_ENTRY(exit) (void) +{ +} + +void +PANGO_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 (syriac_engine_fc_type, NULL); + else + return NULL; +} diff --git a/modules/syriac/syriac-ot.c b/modules/syriac/syriac-ot.c new file mode 100644 index 00000000..6de4aa13 --- /dev/null +++ b/modules/syriac/syriac-ot.c @@ -0,0 +1,362 @@ +/* Pango + * syriac-ot.h: Determine what OpenType features to apply to characters based + * on the rules for Syriac from the OpenType standard. + * + * Copyright (C) 2004 Emil Soleyman-Zomalan + * Author: Emil Soleyman-Zomalan + * + * This file is based on the Arabic shaping code from FreeType 1 tree; original + * copyright notice: + * + * The FreeType project -- a free and portable quality TrueType renderer. + * + * Copyright 1996-2000 by + * D. Turner, R.Wilhelm, and W. Lemberg + * + * The code, like the FreeType code it is derived from is dual-licensed + * under the GNU Public License and the FreeType license. See see + * pango/opentype/FT-license.txt for full details of the FreeType + * license. + */ + +#include "syriac-ot.h" + +/* Here a table of the joining classes for characters in the range + * U+0700 - U+074F. + * + * The following character also has a joining class: + * + * U+200C ZERO WIDTH NON-JOINER -> causing + * + * All other characters are given the joining class `none'. + */ +JoiningClass syriac[] = +{ + /* U+0700 */ + none, none, none, none, + none, none, none, none, + none, none, none, none, + none, none, none, transparent, + + /* U+0710 */ + right, none, dual, dual, + dual, right, right, right, + right, right, dual, dual, + dual, dual, right, dual, + + /* U+0720 */ + dual, dual, dual, dual, + dual, dual, dual, dual, + right, dual, right, dual, + right, none, none, none, + + /* U+0730 */ + transparent, transparent, transparent, transparent, + transparent, transparent, transparent, transparent, + transparent, transparent, transparent, transparent, + transparent, transparent, transparent, transparent, + + /* U+0740 */ + transparent, transparent, transparent, transparent, + transparent, transparent, transparent, transparent, + transparent, transparent, transparent, none, + none, right, dual, dual +}; + +/* `direction' can be -1, 0, or 1 to indicate the last non-transparent + * glyph, the current glyph, and the next non-transparent glyph, + * respectively. + */ +static JoiningClass +Get_Joining_Class (gunichar* string, + int pos, + int length, + int direction) +{ + JoiningClass j; + + while (1) + { + if (pos == 0 && direction < 0) + return none; + + pos += direction; + + if (pos >= length) + return none; + + if (string[pos] < 0x0700 || + string[pos] >= 0x074F) + { + if (string[pos] == 0x200C) + return causing; + else + return none; + } + else + j = syriac[string[pos] - 0x0700]; + + if (!direction || j != transparent) + return j; + } +} + + +/* The rules here are roughly based on the Arabic rules from the Unicode + * 2.0 standard (which differ from the Unicode-4.0 rules), augmented + * with the Syriac rules from the Unicode-4.0 standard. The numbers + * R1...R11 below do not correspond to either the Arabic or the Syriac + * rule numbering from the Unicode standard. + * + * Characters are here specified as appearing in the byte stream, i.e. + * *not* in visual order. Joining classes are given in angle brackets, + * glyph forms in square brackets. Glyphs affected by a specific rule are + * enclosed with vertical bars. + * + * + * Glyphs: 0x0715 (Dalath), 0x0716 (Dalath Rish), 0x072A (Rish), + * 0x0722 (Nun), 0x071F (Kaph) + * + * + * R1: + * + * apply joining rules for + * -> [shape1] [shape2] + * -> [shape1] [isolated] [shape2] + * + * + * R2: <0x0722|0x071F> + * -> [isolated] + * + * The Nun and Kaph characters each have 3 different glyphs + * with two of those glyphs coming at the final position. + * However, one of those final glyphs should really be of the + * isolated glyph form where the preceding character cannot be + * joined to and there is no next character. + * + * This rule exists to combine similar exception for both + * characters without increasing the complexity in the other + * rules. + * + * + * R3: && || + * + * -> [final2] + * + * If the preceding glyph cannot be joined to the current + * glyph and the preceding character is not a Dalath, Rish, + * or Dotless Dalath Rish, then the Alaph takes this contextual + * position. + * + * The [final2] joining rule is placed ahead of the [final] to + * give it greater precedence when choosing the correct glyph. + * If it comes after the [final] rule, the incorrect glyph is + * inserted into position. + * + * + * R4: <0x0715|0x0715|0x072A> || + * + * -> [final3] + * + * If the previous glyph is a Dalath, Rish, or Dotless Dalath + * Rish, then the Alaph takes this contextual position. + * + * The [final3] joining rule is placed ahead of the [final] to + * give it greater precedence when choosing the correct glyph. + * If it comes after the [final] rule, the incorrect glyph is + * inserted into position. + * + * + * R5: || + * + * -> [final] + * + * + * R6: || + * + * -> [final] + * + * + * R7: || + * + * -> [medial] + * + * + * R8: || + * + * -> [medial2] + * + * If the Alaph glyph falls in the middle of a Syriac word and + * the preceding character cannot be joined to, then the Alaph + * takes this contextual position. + * + * + * R9: || + * + * -> [initial] + * + * + * R10: || + * + * -> [initial] + * + * + * R11: -> [isolated] + * + * This joining rule is placed at the end of these features + * because when it is placed at the beginning of all of them + * it tends to break the cursive nature of Syriac writing -- + * it inserts the isolated glyph of each character into that + * position with no joining occurring all throughout a text + * document. + */ + +FT_Error +syriac_assign_properties (gunichar *string, + gulong *properties, + int length) +{ + JoiningClass previous, current, next; + int i; + + if (!string || !properties || length == 0) + return FT_Err_Invalid_Argument; + + for (i = 0; i < length; i++) + { + previous = Get_Joining_Class (string, i, length, -1); + current = Get_Joining_Class (string, i, length, 0); + next = Get_Joining_Class (string, i, length, 1); + + /* R1 */ + + if (current == transparent) + { + properties[i] |= isolated_p; + continue; + } + + /* R2 */ + + if (string[i] == 0x0722 || + string[i] == 0x071F) + if (previous == causing || + previous == right) + if (!(next == causing || + next == right || + next == dual)) + { + properties[i] |= isolated_p; + continue; + } + + /* R3 */ + + if (string[i] == 0x0710) + if (previous == causing || + previous == right) + if (!(string[i - 1] == 0x0715 || + string[i - 1] == 0x0716 || + string[i - 1] == 0x072A)) + { + properties[i] |= final2_p; + continue; + } + + /* R4 */ + + if (string[i] == 0x0710) + if (previous == causing || + previous == right) + if (string[i - 1] == 0x0715 || + string[i - 1] == 0x0716 || + string[i - 1] == 0x072A) + { + properties[i] |= final3_p; + continue; + } + + /* R5 */ + + if (previous == causing || + previous == right || + previous == dual) + if (current == right) + { + properties[i] |= final_p; + continue; + } + + /* R6 */ + + if (previous == causing || + previous == right || + previous == dual) + if (current == dual) + if (!(next == causing || + next == right || + next == dual )) + { + properties[i] |= final_p; + continue; + } + + /* R7 */ + + if (previous == causing || + previous == left || + previous == dual) + if (current == dual) + if (next == causing || + next == right || + next == dual ) + { + properties[i] |= medial_p; + continue; + } + + /* R8 */ + + if (string[i] == 0x0710) + if (previous == causing || + previous == right) + if (next == causing || + next == right || + next == dual) + { + properties[i] |= medial2_p; + continue; + } + + /* R9 */ + + if (current == left) + if (next == causing || + next == right || + next == dual) + { + properties[i] |= initial_p; + continue; + } + + /* R10 */ + + if (!(previous == causing || + previous == left || + previous == dual )) + if (current == dual) + if (next == causing || + next == right || + next == dual) + { + properties[i] |= initial_p; + continue; + } + + /* R11 */ + + properties[i] |= isolated_p; + } + + return FT_Err_Ok; +} diff --git a/modules/syriac/syriac-ot.h b/modules/syriac/syriac-ot.h new file mode 100644 index 00000000..17efd18e --- /dev/null +++ b/modules/syriac/syriac-ot.h @@ -0,0 +1,69 @@ +/* Pango + * syriac-ot.h: Determine what OpenType features to apply to characters based + * on the rules for Syriac from the OpenType standard. + * + * Copyright (C) 2004 Emil Soleyman-Zomalan + * Author: Emil Soleyman-Zomalan + * + * This file is based on the Arabic shaping code from FreeType 1 tree; original + * copyright notice: + * + * The FreeType project -- a free and portable quality TrueType renderer. + * + * Copyright 1996-2000 by + * D. Turner, R.Wilhelm, and W. Lemberg + * + * The code, like the FreeType code it is derived from is dual-licensed + * under the GNU Public License and the FreeType license. See see + * pango/opentype/FT-license.txt for full details of the FreeType + * license. + */ + +#ifndef __SYRIAC_OT_H__ +#define __SYRIAC_OT_H__ + +#include + +G_BEGIN_DECLS + +typedef enum +{ + isolated = 1 << 0, /* nominal */ + final = 1 << 1, /* right_joining */ + initial = 1 << 2, /* left_joining */ + medial = 1 << 3, /* double_joining */ + medial2 = 1 << 4, /* double_joining, applies to Alaph only */ + final2 = 1 << 5, /* right_joining, applies to Alaph only */ + final3 = 1 << 6 /* right_joining, applies to Alaph only */ +} JoiningType; + +/* A glyph's property value as needed by e.g. TT_GSUB_Apply_String() + specifies which features should *not* be applied */ +typedef enum +{ + isolated_p = final | initial | medial | medial2 | final2 | final3, + final_p = isolated | initial | medial | medial2 | final2 | final3, + initial_p = isolated | final | medial | medial2 | final2 | final3, + medial_p = isolated | final | initial | medial2 | final2 | final3, + medial2_p = isolated | final | initial | medial | final2 | final3, + final2_p = isolated | final | initial | medial | medial2 | final3, + final3_p = isolated | final | initial | medial | medial2 | final2 +} SyriacGlyphForm; + +typedef enum +{ + right, + left, /* not used */ + dual, + causing, + none, + transparent +} JoiningClass; + +FT_Error syriac_assign_properties (gunichar *string, + gulong *properties, + int length); + +G_END_DECLS + +#endif /* __SYRIAC_OT_H__ */ -- cgit v1.2.1