summaryrefslogtreecommitdiff
path: root/modules/indic
diff options
context:
space:
mode:
authorRobert Brady <rbrady@src.gnome.org>2000-11-08 06:07:47 +0000
committerRobert Brady <rbrady@src.gnome.org>2000-11-08 06:07:47 +0000
commit452359df74d9ab351b010a58693e597a53aa6362 (patch)
tree0011ec5c2192c96d27663cdd2a945a784f8920de /modules/indic
parent28b8f5db1a22d8ccefb4a88bb0f16ea3d84afade (diff)
downloadpango-452359df74d9ab351b010a58693e597a53aa6362.tar.gz
Shiny new Indic shapers!
Diffstat (limited to 'modules/indic')
-rw-r--r--modules/indic/.cvsignore6
-rw-r--r--modules/indic/Makefile.am61
-rw-r--r--modules/indic/bengali-x.c359
-rw-r--r--modules/indic/bengali.c359
-rw-r--r--modules/indic/devanagari-x.c411
-rw-r--r--modules/indic/devanagari.c411
-rw-r--r--modules/indic/gujarati-x.c387
-rw-r--r--modules/indic/gujarati.c387
-rw-r--r--modules/indic/gurmukhi-x.c301
-rw-r--r--modules/indic/gurmukhi.c301
-rw-r--r--modules/indic/myanmar-x.c281
-rw-r--r--modules/indic/myanmar.c281
-rw-r--r--modules/indic/pango-indic-script.h40
13 files changed, 3585 insertions, 0 deletions
diff --git a/modules/indic/.cvsignore b/modules/indic/.cvsignore
new file mode 100644
index 00000000..6e5ca7ed
--- /dev/null
+++ b/modules/indic/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+.deps
+.libs
+*.lo
+*.la
diff --git a/modules/indic/Makefile.am b/modules/indic/Makefile.am
new file mode 100644
index 00000000..f593b566
--- /dev/null
+++ b/modules/indic/Makefile.am
@@ -0,0 +1,61 @@
+## Process this file with automake to create Makefile.in.
+
+sources = \
+ myanmar.c \
+ gurmukhi.c \
+ bengali.c \
+ gujarati.c \
+ devanagari.c \
+ pango-indic-script.h
+
+if INCLUDE_INDIC
+noinst_LTLIBRARIES = libpango-myanmar.la libpango-gurmukhi.la \
+ libpango-bengali.la \
+ libpango-devanagari.la \
+ libpango-gujarati.la
+moddefine = -DMODULE_PREFIX
+else
+moduledir = $(libdir)/pango/modules
+module_LTLIBRARIES = pango-myanmar.la pango-gurmukhi.la \
+ pango-bengali.la \
+ pango-devanagari.la \
+ pango-gujarati.la
+endif
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/pango/ $(moddefine)
+
+pango_devanagari_la_LDFLAGS = -rpath $(libdir) -export-dynamic -avoid-version -module
+pango_devanagari_la_SOURCES = devanagari.c
+
+libpango_devanagari_la_SOURCES = devanagari.c
+
+
+pango_myanmar_la_LDFLAGS = -rpath $(libdir) -export-dynamic -avoid-version -module
+pango_myanmar_la_SOURCES = myanmar.c
+
+libpango_myanmar_la_SOURCES = myanmar.c
+
+
+pango_gurmukhi_la_LDFLAGS = -rpath $(libdir) -export-dynamic -avoid-version -module
+pango_gurmukhi_la_SOURCES = gurmukhi.c
+
+libpango_gurmukhi_la_SOURCES = gurmukhi.c
+
+
+
+
+pango_bengali_la_LDFLAGS = -rpath $(libdir) -export-dynamic -avoid-version -module
+pango_bengali_la_SOURCES = bengali.c
+
+libpango_bengali_la_SOURCES = bengali.c
+
+
+
+
+
+
+pango_gujarati_la_LDFLAGS = -rpath $(libdir) -export-dynamic -avoid-version -module
+pango_gujarati_la_SOURCES = gujarati.c
+
+libpango_gujarati_la_SOURCES = gujarati.c
+
diff --git a/modules/indic/bengali-x.c b/modules/indic/bengali-x.c
new file mode 100644
index 00000000..05e430f3
--- /dev/null
+++ b/modules/indic/bengali-x.c
@@ -0,0 +1,359 @@
+/* Pango - Bengali module
+ * bengali.c:
+ *
+ * Copyright (C) 2000 Robert Brady,
+ * (C) 2000 SuSE Linux Ltd.
+ *
+ * Author: Robert Brady <rwb197@zepler.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * Licence as published by the Free Software Foundation; either
+ * version 2 of the licence, 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
+ * Lesser General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * Licence along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * This is the renderer for Bengali script.
+ *
+ * This script is used to write many languages including the
+ * following.
+ *
+ * as Assamese
+ * bn Bengali
+ * kha Khasi
+ * mni Manipuri
+ * mun Munda
+ * sat Santali
+ *
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+#include "pango-indic.h"
+
+#define SCRIPT_STRING "Bengali"
+#define ISCII_BASED
+#define RANGE_START 0x980
+#define RANGE_SIZE 0x80
+
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gboolean is_vowel_half (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+static gboolean vowel_split (gunichar i, gunichar *a, gunichar *b);
+
+static PangoIndicScript script = {
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ &vowel_sign_to_matra,
+ &is_vowel_half,
+ &vowel_split,
+};
+
+static gunichar
+vowel_sign_to_matra (gunichar i)
+{
+ if (!is_vowel_sign (i))
+ return i;
+ return i + 0x987 - 0x9c8;
+}
+
+gboolean
+vowel_split (gunichar i, gunichar *a, gunichar *b)
+{
+ if (i == 0x9cb || i == 0x9cc) {
+ if (a)
+ *a = 0x9c7;
+ if (b) {
+ if (i == 0x9cc)
+ *b = 0xe9d7;
+ else
+ *b = 0xe9be;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define RA_SUPERSCRIPT 0xe9ff
+#define RA_SUBSCRIPT 0xe9fe
+
+static char *default_charset = "iso10646-bng";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_indic_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ pango_coverage_set (result, 0x10000, PANGO_COVERAGE_EXACT);
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0x9BE && i <= 0x9Cc) || (i >= 0x9E2 && i <= 0x9E3);
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0x995 && i <= 0x9b9) || (i >= 0x9dc && i <= 0x9df) || (i >= 0x9f0 && i <= 0x09f1);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0x985 && i <= 0x994);
+}
+
+static gboolean
+is_vowel_half (gunichar i)
+{
+ return (i == 0xe9d7) || (i == 0xe9be) || (i == 0x9d7);
+}
+
+static int
+is_prefixing_vowel (gunichar what)
+{
+ return (what == 0x9bf) || (what == 0x9c7) || (what == 0x9c8);
+}
+
+static void
+pango_indic_make_ligs (gunichar * start, gunichar * end)
+{
+ int num = end - start;
+ int i;
+
+ for (i = 0; i < (end - start); i++)
+ {
+ gunichar t0 = pango_indic_get_char (start + i, end);
+ gunichar t1 = pango_indic_get_char (start + 1 + i, end);
+ gunichar t2 = pango_indic_get_char (start + 2 + i, end);
+
+ if ((t0 == VIRAMA) && (t1 == 0x9af))
+ {
+ start[i+0] = 0;
+ start[i+1] = 0xe9fd;
+ }
+ }
+
+ if (start[0] == RA && start[1] == VIRAMA && is_consonant (start[2]))
+ {
+ start[0] = 0;
+ start[1] = start[2];
+ start[2] = RA_SUPERSCRIPT;
+ }
+
+ for (i = 0; i < (end - start - 1); i++)
+ {
+ if (start[i] == VIRAMA)
+ {
+ if (start[i+1] == RA)
+ {
+ start[i] = 0;
+ start[i+1] = RA_SUBSCRIPT;
+ break;
+ }
+ }
+ }
+
+}
+
+static void
+pango_indic_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis, PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i, k;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc,
+ &n_glyph, glyphs);
+ pango_indic_convert_vowels (&script, TRUE, &n_glyph, wc,
+ pango_x_has_glyph (font,
+ PANGO_X_MAKE_GLYPH (subfont, 0xc9bd)));
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_glyph; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_make_ligs (syls[i], syls[i+1]);
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters);
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_indic_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_indic_engine_shape;
+ result->get_coverage = pango_indic_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_indic_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_indic_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_indic_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_indic_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_indic_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
+
diff --git a/modules/indic/bengali.c b/modules/indic/bengali.c
new file mode 100644
index 00000000..05e430f3
--- /dev/null
+++ b/modules/indic/bengali.c
@@ -0,0 +1,359 @@
+/* Pango - Bengali module
+ * bengali.c:
+ *
+ * Copyright (C) 2000 Robert Brady,
+ * (C) 2000 SuSE Linux Ltd.
+ *
+ * Author: Robert Brady <rwb197@zepler.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * Licence as published by the Free Software Foundation; either
+ * version 2 of the licence, 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
+ * Lesser General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * Licence along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * This is the renderer for Bengali script.
+ *
+ * This script is used to write many languages including the
+ * following.
+ *
+ * as Assamese
+ * bn Bengali
+ * kha Khasi
+ * mni Manipuri
+ * mun Munda
+ * sat Santali
+ *
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+#include "pango-indic.h"
+
+#define SCRIPT_STRING "Bengali"
+#define ISCII_BASED
+#define RANGE_START 0x980
+#define RANGE_SIZE 0x80
+
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gboolean is_vowel_half (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+static gboolean vowel_split (gunichar i, gunichar *a, gunichar *b);
+
+static PangoIndicScript script = {
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ &vowel_sign_to_matra,
+ &is_vowel_half,
+ &vowel_split,
+};
+
+static gunichar
+vowel_sign_to_matra (gunichar i)
+{
+ if (!is_vowel_sign (i))
+ return i;
+ return i + 0x987 - 0x9c8;
+}
+
+gboolean
+vowel_split (gunichar i, gunichar *a, gunichar *b)
+{
+ if (i == 0x9cb || i == 0x9cc) {
+ if (a)
+ *a = 0x9c7;
+ if (b) {
+ if (i == 0x9cc)
+ *b = 0xe9d7;
+ else
+ *b = 0xe9be;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define RA_SUPERSCRIPT 0xe9ff
+#define RA_SUBSCRIPT 0xe9fe
+
+static char *default_charset = "iso10646-bng";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_indic_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ pango_coverage_set (result, 0x10000, PANGO_COVERAGE_EXACT);
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0x9BE && i <= 0x9Cc) || (i >= 0x9E2 && i <= 0x9E3);
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0x995 && i <= 0x9b9) || (i >= 0x9dc && i <= 0x9df) || (i >= 0x9f0 && i <= 0x09f1);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0x985 && i <= 0x994);
+}
+
+static gboolean
+is_vowel_half (gunichar i)
+{
+ return (i == 0xe9d7) || (i == 0xe9be) || (i == 0x9d7);
+}
+
+static int
+is_prefixing_vowel (gunichar what)
+{
+ return (what == 0x9bf) || (what == 0x9c7) || (what == 0x9c8);
+}
+
+static void
+pango_indic_make_ligs (gunichar * start, gunichar * end)
+{
+ int num = end - start;
+ int i;
+
+ for (i = 0; i < (end - start); i++)
+ {
+ gunichar t0 = pango_indic_get_char (start + i, end);
+ gunichar t1 = pango_indic_get_char (start + 1 + i, end);
+ gunichar t2 = pango_indic_get_char (start + 2 + i, end);
+
+ if ((t0 == VIRAMA) && (t1 == 0x9af))
+ {
+ start[i+0] = 0;
+ start[i+1] = 0xe9fd;
+ }
+ }
+
+ if (start[0] == RA && start[1] == VIRAMA && is_consonant (start[2]))
+ {
+ start[0] = 0;
+ start[1] = start[2];
+ start[2] = RA_SUPERSCRIPT;
+ }
+
+ for (i = 0; i < (end - start - 1); i++)
+ {
+ if (start[i] == VIRAMA)
+ {
+ if (start[i+1] == RA)
+ {
+ start[i] = 0;
+ start[i+1] = RA_SUBSCRIPT;
+ break;
+ }
+ }
+ }
+
+}
+
+static void
+pango_indic_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis, PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i, k;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc,
+ &n_glyph, glyphs);
+ pango_indic_convert_vowels (&script, TRUE, &n_glyph, wc,
+ pango_x_has_glyph (font,
+ PANGO_X_MAKE_GLYPH (subfont, 0xc9bd)));
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_glyph; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_make_ligs (syls[i], syls[i+1]);
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters);
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_indic_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_indic_engine_shape;
+ result->get_coverage = pango_indic_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_indic_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_indic_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_indic_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_indic_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_indic_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
+
diff --git a/modules/indic/devanagari-x.c b/modules/indic/devanagari-x.c
new file mode 100644
index 00000000..028c432e
--- /dev/null
+++ b/modules/indic/devanagari-x.c
@@ -0,0 +1,411 @@
+/* Pango - Devanagari module
+ *
+ * Copyright (C) 2000 SuSE Linux Ltd
+ * Author: Robert Brady <robert@suse.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * Licence as published by the Free Software Foundation; either
+ * version 2.1 of the Licence, 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
+ * Lesser General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * Licence along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * This is the renderer for the Devanagari script.
+ *
+ * This script is used to write many languages, including the
+ * following.
+ *
+ * awa Awadhi bh Bihari bra Braj Bhasa
+ * gon Gondhi hi Hindi kok Konkani
+ * mr Marathi new Newari ne Nepali
+ * sa Sanskrit sat Santali
+ *
+ * For a description of the rendering algorithm, see section 9.1 of
+ * /The Unicode Standard Version 3.0/.
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+
+#define RANGE_START 0x900
+#define RANGE_SIZE 0x80
+
+#define ISCII_BASED
+#define SCRIPT_STRING "Devanagari"
+
+#include "pango-indic.h"
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+
+static PangoIndicScript script =
+{
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ &vowel_sign_to_matra,
+ NULL, /* no split vowels for Devanagari */
+};
+
+#define INTERMEDIATE_HALF_FORM_OFFSET 0xf000
+#define FINAL_HALF_FORM_OFFSET 0xe000
+
+#define RA_SUPERSCRIPT 0xc97f
+#define RA_SUBSCRIPT 0xc97e
+
+static char *default_charset = "iso10646-dev";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+ {ZERO_WIDTH_JOINER, ZERO_WIDTH_JOINER, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_indic_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ pango_coverage_set (result, ZERO_WIDTH_JOINER, PANGO_COVERAGE_EXACT);
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0x93E && i <= 0x94c) || (i >= 0x962 && i <= 0x963);
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0x915 && i <= 0x939) || (i >= 0x958 && i <= 0x95f);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0x905 && i <= 0x914);
+}
+
+static gunichar
+vowel_sign_to_matra (gunichar i)
+{
+ if (is_vowel_sign (i))
+ return i + 0x905 - 0x93e;
+ return i;
+}
+
+static gboolean
+is_prefixing_vowel (gunichar i)
+{
+ return i == 0x93f;
+}
+
+static void
+dev_mini_shuffle (gunichar *s, gunichar *e)
+{
+ gunichar *dest = s;
+ while (s < e)
+ {
+ if (*s)
+ {
+ *dest = *s;
+ dest++;
+ }
+ s++;
+ }
+ while (dest < e)
+ {
+ *dest = 0;
+ dest++;
+ }
+}
+
+static int
+is_intermediate_form (int q)
+{
+ return (q >= 0xf000 && q <= 0xffff);
+}
+
+static int
+is_consonantal_form (int q)
+{
+ return (q == ZERO_WIDTH_JOINER) || is_consonant (q) || (q >= 0xd000);
+}
+
+static int
+nominal_form (int q)
+{
+ return q - 0xf000;
+}
+
+static int
+half_form (int q)
+{
+ return (q & 0xfff) + 0xe000;
+}
+
+static void
+shuffle_one_along (gunichar *start, gunichar *end)
+{
+ end--;
+ if (*end != 0)
+ fprintf (stderr, "pango devanagari error, please report. bad shuffle!\n");
+ while (end > start)
+ {
+ end[0] = end[-1];
+ end--;
+ }
+ start[0] = 0;
+}
+
+static void
+pango_indic_make_ligs (gunichar * start, gunichar * end)
+{
+ int num = end - start;
+ int i;
+
+ for (i = 0; i < (end - start); i++)
+ {
+ gunichar t0 = pango_indic_get_char (start + i, end);
+ gunichar t1 = pango_indic_get_char (start + 1 + i, end);
+
+ if (is_consonant (t0) && t1 == VIRAMA)
+ {
+ start[i+0] = t0 + INTERMEDIATE_HALF_FORM_OFFSET;
+ start[i+1] = 0;
+ }
+ }
+
+ if (num > 2 && start[0] == INTERMEDIATE_HALF_FORM_OFFSET + RA)
+ {
+ for (i=1;i<num;i++)
+ start[i-1] = start[i];
+
+ start[num-1] = RA_SUPERSCRIPT;
+ }
+
+ dev_mini_shuffle (start, end);
+
+ for (i = 0; i < (end - start - 1); i++)
+ if (is_intermediate_form (start[i]))
+ {
+ if (start[i+1] == RA)
+ {
+ start[i] = nominal_form (start[i]);
+ start[i+1] = RA_SUBSCRIPT;
+ }
+ else if (start[i+1] == (RA + INTERMEDIATE_HALF_FORM_OFFSET))
+ {
+ start[i] = nominal_form (start[i]);
+ start[i+1] = RA_SUBSCRIPT;
+ shuffle_one_along (start+2, end);
+ start[i+2] = VIRAMA;
+ }
+ }
+}
+
+static void
+pango_indic_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis,
+ PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc, &n_glyph,
+ glyphs);
+ pango_indic_convert_vowels (&script, TRUE, &n_glyph, wc,
+ pango_x_has_glyph (font,
+ PANGO_X_MAKE_GLYPH(subfont, 0xc93e)));
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_chars; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_make_ligs (syls[i], syls[i+1]);
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters);
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+#if 0
+ if (i && (wc[i] == VIRAMA) && (wc[i-1] == RA_SUBSCRIPT))
+ {
+ wc[i] = LOWER_VIRAMA_GLYPH;
+ }
+#endif
+ if ((i != (n_glyph - 1)) && is_intermediate_form (wc[i]) &&
+ is_consonantal_form (wc[i+1]))
+ {
+ wc[i] = half_form (wc[i]);
+ }
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_indic_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_indic_engine_shape;
+ result->get_coverage = pango_indic_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_indic_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_indic_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_indic_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_indic_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_indic_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_indic_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
diff --git a/modules/indic/devanagari.c b/modules/indic/devanagari.c
new file mode 100644
index 00000000..028c432e
--- /dev/null
+++ b/modules/indic/devanagari.c
@@ -0,0 +1,411 @@
+/* Pango - Devanagari module
+ *
+ * Copyright (C) 2000 SuSE Linux Ltd
+ * Author: Robert Brady <robert@suse.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * Licence as published by the Free Software Foundation; either
+ * version 2.1 of the Licence, 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
+ * Lesser General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * Licence along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * This is the renderer for the Devanagari script.
+ *
+ * This script is used to write many languages, including the
+ * following.
+ *
+ * awa Awadhi bh Bihari bra Braj Bhasa
+ * gon Gondhi hi Hindi kok Konkani
+ * mr Marathi new Newari ne Nepali
+ * sa Sanskrit sat Santali
+ *
+ * For a description of the rendering algorithm, see section 9.1 of
+ * /The Unicode Standard Version 3.0/.
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+
+#define RANGE_START 0x900
+#define RANGE_SIZE 0x80
+
+#define ISCII_BASED
+#define SCRIPT_STRING "Devanagari"
+
+#include "pango-indic.h"
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+
+static PangoIndicScript script =
+{
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ &vowel_sign_to_matra,
+ NULL, /* no split vowels for Devanagari */
+};
+
+#define INTERMEDIATE_HALF_FORM_OFFSET 0xf000
+#define FINAL_HALF_FORM_OFFSET 0xe000
+
+#define RA_SUPERSCRIPT 0xc97f
+#define RA_SUBSCRIPT 0xc97e
+
+static char *default_charset = "iso10646-dev";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+ {ZERO_WIDTH_JOINER, ZERO_WIDTH_JOINER, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_indic_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ pango_coverage_set (result, ZERO_WIDTH_JOINER, PANGO_COVERAGE_EXACT);
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0x93E && i <= 0x94c) || (i >= 0x962 && i <= 0x963);
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0x915 && i <= 0x939) || (i >= 0x958 && i <= 0x95f);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0x905 && i <= 0x914);
+}
+
+static gunichar
+vowel_sign_to_matra (gunichar i)
+{
+ if (is_vowel_sign (i))
+ return i + 0x905 - 0x93e;
+ return i;
+}
+
+static gboolean
+is_prefixing_vowel (gunichar i)
+{
+ return i == 0x93f;
+}
+
+static void
+dev_mini_shuffle (gunichar *s, gunichar *e)
+{
+ gunichar *dest = s;
+ while (s < e)
+ {
+ if (*s)
+ {
+ *dest = *s;
+ dest++;
+ }
+ s++;
+ }
+ while (dest < e)
+ {
+ *dest = 0;
+ dest++;
+ }
+}
+
+static int
+is_intermediate_form (int q)
+{
+ return (q >= 0xf000 && q <= 0xffff);
+}
+
+static int
+is_consonantal_form (int q)
+{
+ return (q == ZERO_WIDTH_JOINER) || is_consonant (q) || (q >= 0xd000);
+}
+
+static int
+nominal_form (int q)
+{
+ return q - 0xf000;
+}
+
+static int
+half_form (int q)
+{
+ return (q & 0xfff) + 0xe000;
+}
+
+static void
+shuffle_one_along (gunichar *start, gunichar *end)
+{
+ end--;
+ if (*end != 0)
+ fprintf (stderr, "pango devanagari error, please report. bad shuffle!\n");
+ while (end > start)
+ {
+ end[0] = end[-1];
+ end--;
+ }
+ start[0] = 0;
+}
+
+static void
+pango_indic_make_ligs (gunichar * start, gunichar * end)
+{
+ int num = end - start;
+ int i;
+
+ for (i = 0; i < (end - start); i++)
+ {
+ gunichar t0 = pango_indic_get_char (start + i, end);
+ gunichar t1 = pango_indic_get_char (start + 1 + i, end);
+
+ if (is_consonant (t0) && t1 == VIRAMA)
+ {
+ start[i+0] = t0 + INTERMEDIATE_HALF_FORM_OFFSET;
+ start[i+1] = 0;
+ }
+ }
+
+ if (num > 2 && start[0] == INTERMEDIATE_HALF_FORM_OFFSET + RA)
+ {
+ for (i=1;i<num;i++)
+ start[i-1] = start[i];
+
+ start[num-1] = RA_SUPERSCRIPT;
+ }
+
+ dev_mini_shuffle (start, end);
+
+ for (i = 0; i < (end - start - 1); i++)
+ if (is_intermediate_form (start[i]))
+ {
+ if (start[i+1] == RA)
+ {
+ start[i] = nominal_form (start[i]);
+ start[i+1] = RA_SUBSCRIPT;
+ }
+ else if (start[i+1] == (RA + INTERMEDIATE_HALF_FORM_OFFSET))
+ {
+ start[i] = nominal_form (start[i]);
+ start[i+1] = RA_SUBSCRIPT;
+ shuffle_one_along (start+2, end);
+ start[i+2] = VIRAMA;
+ }
+ }
+}
+
+static void
+pango_indic_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis,
+ PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc, &n_glyph,
+ glyphs);
+ pango_indic_convert_vowels (&script, TRUE, &n_glyph, wc,
+ pango_x_has_glyph (font,
+ PANGO_X_MAKE_GLYPH(subfont, 0xc93e)));
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_chars; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_make_ligs (syls[i], syls[i+1]);
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters);
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+#if 0
+ if (i && (wc[i] == VIRAMA) && (wc[i-1] == RA_SUBSCRIPT))
+ {
+ wc[i] = LOWER_VIRAMA_GLYPH;
+ }
+#endif
+ if ((i != (n_glyph - 1)) && is_intermediate_form (wc[i]) &&
+ is_consonantal_form (wc[i+1]))
+ {
+ wc[i] = half_form (wc[i]);
+ }
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_indic_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_indic_engine_shape;
+ result->get_coverage = pango_indic_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_indic_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_indic_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_indic_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_indic_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_indic_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_indic_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
diff --git a/modules/indic/gujarati-x.c b/modules/indic/gujarati-x.c
new file mode 100644
index 00000000..0b72babd
--- /dev/null
+++ b/modules/indic/gujarati-x.c
@@ -0,0 +1,387 @@
+/* Pango - Gujarati module
+ *
+ * Copyright (C) 2000 SuSE Linux Ltd
+ * Author: Robert Brady <robert@suse.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * Licence as published by the Free Software Foundation; either
+ * version 2.1 of the Licence, 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
+ * Lesser General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * Licence along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+
+#define RANGE_START 0xA80
+#define RANGE_SIZE 0x80
+
+#define ISCII_BASED
+#define SCRIPT_STRING "Gujarati"
+
+#include "pango-indic.h"
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+
+static PangoIndicScript script = {
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ NULL, /* vowel sign to matra must die! */
+ NULL, /* no split vowels for Devanagari */
+};
+
+#define INTERMEDIATE_HALF_FORM_OFFSET 0xf000
+#define FINAL_HALF_FORM_OFFSET 0xe000
+#define RA_SUPERSCRIPT 0xeaff
+#define RA_SUBSCRIPT 0xeafe
+
+static char *default_charset = "iso10646-guj";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+ {ZERO_WIDTH_JOINER, ZERO_WIDTH_JOINER, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_indic_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ pango_coverage_set (result, ZERO_WIDTH_JOINER, PANGO_COVERAGE_EXACT);
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0xABE && i <= 0xACC);
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0xA95 && i <= 0xAB9) || (i == 0xAE0);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0xA85 && i <= 0xA94);
+}
+
+static gboolean
+is_prefixing_vowel (gunichar i)
+{
+ return i == 0xABF;
+}
+
+static void
+dev_mini_shuffle (gunichar *s, gunichar *e)
+{
+ gunichar *dest = s;
+ while (s < e)
+ {
+ if (*s)
+ {
+ *dest = *s;
+ dest++;
+ }
+ s++;
+ }
+ while (dest < e)
+ {
+ *dest = 0;
+ dest++;
+ }
+}
+
+static int
+is_intermediate_form (int q)
+{
+ return (q >= 0xf000 && q <= 0xffff);
+}
+
+static int
+is_consonantal_form (int q)
+{
+ return (q == ZERO_WIDTH_JOINER) || is_consonant (q) || (q >= 0xc000);
+}
+
+static int
+nominal_form (int q)
+{
+ return q - 0xf000;
+}
+
+static int
+half_form (int q)
+{
+ return (q & 0xfff) + 0xe000;
+}
+
+static void
+shuffle_one_along (gunichar *start, gunichar *end)
+{
+ end--;
+ if (*end != 0)
+ {
+ return;
+ }
+ while (end > start)
+ {
+ end[0] = end[-1];
+ end--;
+ }
+ start[0] = 0;
+}
+
+static void
+pango_indic_make_ligs (gunichar * start, gunichar * end)
+{
+ int num = end - start;
+ int i;
+
+ for (i = 0; i < (end - start); i++)
+ {
+ gunichar t0 = pango_indic_get_char (start + i, end);
+ gunichar t1 = pango_indic_get_char (start + 1 + i, end);
+
+ if (is_consonant (t0) && t1 == VIRAMA)
+ {
+ start[i+0] = t0 + INTERMEDIATE_HALF_FORM_OFFSET;
+ start[i+1] = 0;
+ }
+ }
+
+ while (num && !is_consonant (start[num-1]))
+ {
+ num--;
+ }
+ if (num > 2 && start[0] == INTERMEDIATE_HALF_FORM_OFFSET + RA)
+ {
+ for (i=1;i<num;i++)
+ {
+ start[i-1] = start[i];
+ }
+ start[num-1] = RA_SUPERSCRIPT;
+ }
+
+ dev_mini_shuffle (start, end);
+
+ for (i = 0; i < (end - start - 1); i++)
+ if (is_intermediate_form (start[i]))
+ {
+ if (start[i+1] == RA)
+ {
+ start[i] = nominal_form (start[i]);
+ start[i+1] = RA_SUBSCRIPT;
+ }
+ else if (start[i+1] == (RA + INTERMEDIATE_HALF_FORM_OFFSET))
+ {
+ start[i] = nominal_form (start[i]);
+ start[i+1] = RA_SUBSCRIPT;
+ shuffle_one_along (start+2, end);
+ start[i+2] = VIRAMA;
+ }
+ }
+}
+
+static void
+pango_indic_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis, PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc,
+ &n_glyph, glyphs);
+ pango_indic_convert_vowels (&script, TRUE, &n_glyph, wc, FALSE);
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_chars; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_make_ligs (syls[i], syls[i+1]);
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters);
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+ if ((i != (n_glyph - 1)) && is_intermediate_form (wc[i]) &&
+ is_consonantal_form (wc[i+1]))
+ {
+ wc[i] = half_form (wc[i]);
+ }
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_indic_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_indic_engine_shape;
+ result->get_coverage = pango_indic_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_indic_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_indic_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_indic_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_indic_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_indic_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_indic_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
diff --git a/modules/indic/gujarati.c b/modules/indic/gujarati.c
new file mode 100644
index 00000000..0b72babd
--- /dev/null
+++ b/modules/indic/gujarati.c
@@ -0,0 +1,387 @@
+/* Pango - Gujarati module
+ *
+ * Copyright (C) 2000 SuSE Linux Ltd
+ * Author: Robert Brady <robert@suse.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * Licence as published by the Free Software Foundation; either
+ * version 2.1 of the Licence, 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
+ * Lesser General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * Licence along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+
+#define RANGE_START 0xA80
+#define RANGE_SIZE 0x80
+
+#define ISCII_BASED
+#define SCRIPT_STRING "Gujarati"
+
+#include "pango-indic.h"
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+
+static PangoIndicScript script = {
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ NULL, /* vowel sign to matra must die! */
+ NULL, /* no split vowels for Devanagari */
+};
+
+#define INTERMEDIATE_HALF_FORM_OFFSET 0xf000
+#define FINAL_HALF_FORM_OFFSET 0xe000
+#define RA_SUPERSCRIPT 0xeaff
+#define RA_SUBSCRIPT 0xeafe
+
+static char *default_charset = "iso10646-guj";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+ {ZERO_WIDTH_JOINER, ZERO_WIDTH_JOINER, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_indic_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ pango_coverage_set (result, ZERO_WIDTH_JOINER, PANGO_COVERAGE_EXACT);
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0xABE && i <= 0xACC);
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0xA95 && i <= 0xAB9) || (i == 0xAE0);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0xA85 && i <= 0xA94);
+}
+
+static gboolean
+is_prefixing_vowel (gunichar i)
+{
+ return i == 0xABF;
+}
+
+static void
+dev_mini_shuffle (gunichar *s, gunichar *e)
+{
+ gunichar *dest = s;
+ while (s < e)
+ {
+ if (*s)
+ {
+ *dest = *s;
+ dest++;
+ }
+ s++;
+ }
+ while (dest < e)
+ {
+ *dest = 0;
+ dest++;
+ }
+}
+
+static int
+is_intermediate_form (int q)
+{
+ return (q >= 0xf000 && q <= 0xffff);
+}
+
+static int
+is_consonantal_form (int q)
+{
+ return (q == ZERO_WIDTH_JOINER) || is_consonant (q) || (q >= 0xc000);
+}
+
+static int
+nominal_form (int q)
+{
+ return q - 0xf000;
+}
+
+static int
+half_form (int q)
+{
+ return (q & 0xfff) + 0xe000;
+}
+
+static void
+shuffle_one_along (gunichar *start, gunichar *end)
+{
+ end--;
+ if (*end != 0)
+ {
+ return;
+ }
+ while (end > start)
+ {
+ end[0] = end[-1];
+ end--;
+ }
+ start[0] = 0;
+}
+
+static void
+pango_indic_make_ligs (gunichar * start, gunichar * end)
+{
+ int num = end - start;
+ int i;
+
+ for (i = 0; i < (end - start); i++)
+ {
+ gunichar t0 = pango_indic_get_char (start + i, end);
+ gunichar t1 = pango_indic_get_char (start + 1 + i, end);
+
+ if (is_consonant (t0) && t1 == VIRAMA)
+ {
+ start[i+0] = t0 + INTERMEDIATE_HALF_FORM_OFFSET;
+ start[i+1] = 0;
+ }
+ }
+
+ while (num && !is_consonant (start[num-1]))
+ {
+ num--;
+ }
+ if (num > 2 && start[0] == INTERMEDIATE_HALF_FORM_OFFSET + RA)
+ {
+ for (i=1;i<num;i++)
+ {
+ start[i-1] = start[i];
+ }
+ start[num-1] = RA_SUPERSCRIPT;
+ }
+
+ dev_mini_shuffle (start, end);
+
+ for (i = 0; i < (end - start - 1); i++)
+ if (is_intermediate_form (start[i]))
+ {
+ if (start[i+1] == RA)
+ {
+ start[i] = nominal_form (start[i]);
+ start[i+1] = RA_SUBSCRIPT;
+ }
+ else if (start[i+1] == (RA + INTERMEDIATE_HALF_FORM_OFFSET))
+ {
+ start[i] = nominal_form (start[i]);
+ start[i+1] = RA_SUBSCRIPT;
+ shuffle_one_along (start+2, end);
+ start[i+2] = VIRAMA;
+ }
+ }
+}
+
+static void
+pango_indic_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis, PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc,
+ &n_glyph, glyphs);
+ pango_indic_convert_vowels (&script, TRUE, &n_glyph, wc, FALSE);
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_chars; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_make_ligs (syls[i], syls[i+1]);
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters);
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+ if ((i != (n_glyph - 1)) && is_intermediate_form (wc[i]) &&
+ is_consonantal_form (wc[i+1]))
+ {
+ wc[i] = half_form (wc[i]);
+ }
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_indic_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_indic_engine_shape;
+ result->get_coverage = pango_indic_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_indic_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_indic_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_indic_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_indic_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_indic_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_indic_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
diff --git a/modules/indic/gurmukhi-x.c b/modules/indic/gurmukhi-x.c
new file mode 100644
index 00000000..e448fb22
--- /dev/null
+++ b/modules/indic/gurmukhi-x.c
@@ -0,0 +1,301 @@
+/* Pango - Gurmukhi module
+ * gurmukhi.c:
+ *
+ * Copyright (C) 2000 SuSE Linux Ltd
+ * Author: Robert Brady <robert@suse.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * This is the renderer for Gurmukhi. This script is primarily used
+ * to write the Panjabi (pa) language.
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+#include "pango-indic.h"
+
+#define RANGE_START 0xa00
+#define RANGE_SIZE 0x80
+#define SCRIPT_STRING "Gurmukhi"
+#define ISCII_BASED
+
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gboolean is_vowel_half (gunichar i);
+
+static PangoIndicScript script = {
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ &vowel_sign_to_matra,
+ &is_vowel_half,
+};
+
+#define RA_SUBSCRIPT 0xea7e
+
+static char *default_charset = "iso10646-gur";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_indic_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0xa3e && i <= 0xa4c);
+}
+
+static gunichar
+vowel_sign_to_matra (gunichar i)
+{
+ if (i >= 0xa3e && i <= 0xa4c)
+ return i - 0xa3e + 0xa06;
+ return i;
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0xa15 && i <= 0xa39) ||
+ (i >= 0xa59 && i <= 0xa5e);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0xa05 && i <= 0xa14);
+}
+
+static gboolean
+is_vowel_half (gunichar i)
+{
+ return 0;
+}
+
+static int
+is_prefixing_vowel (gunichar what)
+{
+ return (what == 0xa3f);
+}
+
+static void
+pango_indic_make_ligs (gunichar * start, gunichar * end)
+{
+ int i;
+ for (i = 0; i < (end-start-2);i++)
+ {
+ if (is_consonant (start[i]))
+ {
+ if (start[i+2]==RA && start[i+1]==VIRAMA)
+ {
+ start[i+1] = 0;
+ start[i+2] = RA_SUBSCRIPT;
+ }
+ }
+ }
+}
+
+static void
+pango_indic_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis, PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i, k;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc,
+ &n_glyph, glyphs);
+ pango_indic_convert_vowels (&script, TRUE, &n_glyph, wc, FALSE);
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_glyph; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_make_ligs (syls[i], syls[i+1]);
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters);
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_indic_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_indic_engine_shape;
+ result->get_coverage = pango_indic_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_indic_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_indic_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_indic_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_indic_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_indic_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
diff --git a/modules/indic/gurmukhi.c b/modules/indic/gurmukhi.c
new file mode 100644
index 00000000..e448fb22
--- /dev/null
+++ b/modules/indic/gurmukhi.c
@@ -0,0 +1,301 @@
+/* Pango - Gurmukhi module
+ * gurmukhi.c:
+ *
+ * Copyright (C) 2000 SuSE Linux Ltd
+ * Author: Robert Brady <robert@suse.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * This is the renderer for Gurmukhi. This script is primarily used
+ * to write the Panjabi (pa) language.
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+#include "pango-indic.h"
+
+#define RANGE_START 0xa00
+#define RANGE_SIZE 0x80
+#define SCRIPT_STRING "Gurmukhi"
+#define ISCII_BASED
+
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gboolean is_vowel_half (gunichar i);
+
+static PangoIndicScript script = {
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ &vowel_sign_to_matra,
+ &is_vowel_half,
+};
+
+#define RA_SUBSCRIPT 0xea7e
+
+static char *default_charset = "iso10646-gur";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_indic_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0xa3e && i <= 0xa4c);
+}
+
+static gunichar
+vowel_sign_to_matra (gunichar i)
+{
+ if (i >= 0xa3e && i <= 0xa4c)
+ return i - 0xa3e + 0xa06;
+ return i;
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0xa15 && i <= 0xa39) ||
+ (i >= 0xa59 && i <= 0xa5e);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0xa05 && i <= 0xa14);
+}
+
+static gboolean
+is_vowel_half (gunichar i)
+{
+ return 0;
+}
+
+static int
+is_prefixing_vowel (gunichar what)
+{
+ return (what == 0xa3f);
+}
+
+static void
+pango_indic_make_ligs (gunichar * start, gunichar * end)
+{
+ int i;
+ for (i = 0; i < (end-start-2);i++)
+ {
+ if (is_consonant (start[i]))
+ {
+ if (start[i+2]==RA && start[i+1]==VIRAMA)
+ {
+ start[i+1] = 0;
+ start[i+2] = RA_SUBSCRIPT;
+ }
+ }
+ }
+}
+
+static void
+pango_indic_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis, PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i, k;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc,
+ &n_glyph, glyphs);
+ pango_indic_convert_vowels (&script, TRUE, &n_glyph, wc, FALSE);
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_glyph; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_make_ligs (syls[i], syls[i+1]);
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters);
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_indic_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_indic_engine_shape;
+ result->get_coverage = pango_indic_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_indic_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_indic_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_indic_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_indic_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_indic_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
diff --git a/modules/indic/myanmar-x.c b/modules/indic/myanmar-x.c
new file mode 100644
index 00000000..ae0424c6
--- /dev/null
+++ b/modules/indic/myanmar-x.c
@@ -0,0 +1,281 @@
+/* Pango - Myanmar module
+ * myanmar.c:
+ *
+ * Copyright (C) 2000 SuSE Linux Ltd
+ * Author: Robert Brady <robert@suse.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * This is the renderer for the Burmese (Myanmar) script. This
+ * script is used to write the following languages :
+ *
+ * my Burmese
+ * shn Shan
+ * mkh Mon
+ * pi Pali
+ *
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+#include "pango-indic.h"
+
+#define RANGE_START 0x1000
+#define RANGE_SIZE 0x80
+#define SCRIPT_STRING "Myanmar"
+#define VIRAMA 0x1039
+
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+
+static PangoIndicScript script = {
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ &vowel_sign_to_matra,
+};
+
+static char *default_charset = "iso10646-brm";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0x102c && i <= 0x1032) || (i >= 0x1056 && i <= 0x1059);
+}
+
+static gunichar
+vowel_sign_to_matra (gunichar i)
+{
+ if (i >= 0x102d && i <= 0x1032)
+ return i - 0x102d + 0x1023;
+ return i;
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0x1000 && i <= 0x1020) || (i >= 0x1052 && i <= 0x1053);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0x1021 && i <= 0x102a);
+}
+
+static int
+is_prefixing_vowel (gunichar what)
+{
+ return (what == 0x1031);
+}
+
+static void
+pango_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis, PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i, k;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc,
+ &n_glyph, glyphs);
+ pango_indic_convert_vowels (&script, FALSE, &n_glyph, wc, FALSE);
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_glyph; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ while ((i=pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters)))
+ {
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ }
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_engine_shape;
+ result->get_coverage = pango_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
diff --git a/modules/indic/myanmar.c b/modules/indic/myanmar.c
new file mode 100644
index 00000000..ae0424c6
--- /dev/null
+++ b/modules/indic/myanmar.c
@@ -0,0 +1,281 @@
+/* Pango - Myanmar module
+ * myanmar.c:
+ *
+ * Copyright (C) 2000 SuSE Linux Ltd
+ * Author: Robert Brady <robert@suse.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * This is the renderer for the Burmese (Myanmar) script. This
+ * script is used to write the following languages :
+ *
+ * my Burmese
+ * shn Shan
+ * mkh Mon
+ * pi Pali
+ *
+ */
+
+
+#include <glib.h>
+#include <stdio.h>
+
+#include "pango.h"
+#include "pangox.h"
+#include "pango-indic.h"
+
+#define RANGE_START 0x1000
+#define RANGE_SIZE 0x80
+#define SCRIPT_STRING "Myanmar"
+#define VIRAMA 0x1039
+
+#include "pango-indic-script.h"
+
+static gboolean is_prefixing_vowel (gunichar i);
+static gboolean is_vowel_sign (gunichar i);
+static gunichar vowel_sign_to_matra (gunichar i);
+
+static PangoIndicScript script = {
+ SCRIPT_STRING,
+ &is_prefixing_vowel,
+ &is_vowel_sign,
+ &vowel_sign_to_matra,
+};
+
+static char *default_charset = "iso10646-brm";
+
+static PangoEngineRange pango_indic_range[] =
+{
+ {RANGE_START, RANGE_END, "*"},
+};
+
+SCRIPT_ENGINE_DEFINITION
+
+static PangoCoverage *
+pango_engine_get_coverage (PangoFont * font, const char *lang)
+{
+ gunichar i;
+ PangoCoverage *result = pango_coverage_new ();
+ PangoXSubfont subfont;
+
+ int dev_font = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+
+ if (dev_font)
+ {
+ for (i = RANGE_START; i <= RANGE_END; i++)
+ pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
+
+ }
+
+ return result;
+}
+
+static gboolean
+is_vowel_sign (gunichar i)
+{
+ /* one that combines, whether or not it spaces */
+ return (i >= 0x102c && i <= 0x1032) || (i >= 0x1056 && i <= 0x1059);
+}
+
+static gunichar
+vowel_sign_to_matra (gunichar i)
+{
+ if (i >= 0x102d && i <= 0x1032)
+ return i - 0x102d + 0x1023;
+ return i;
+}
+
+static int
+is_consonant (int i)
+{
+ return (i >= 0x1000 && i <= 0x1020) || (i >= 0x1052 && i <= 0x1053);
+}
+
+static int
+is_ind_vowel (int i)
+{
+ return (i >= 0x1021 && i <= 0x102a);
+}
+
+static int
+is_prefixing_vowel (gunichar what)
+{
+ return (what == 0x1031);
+}
+
+static void
+pango_engine_shape (PangoFont * font,
+ const char *text,
+ int length,
+ PangoAnalysis * analysis, PangoGlyphString * glyphs)
+{
+ PangoXSubfont subfont;
+
+ int n_chars, n_glyph;
+ int lvl;
+ const char *p;
+ int i, k;
+ gunichar *wc;
+ int sb;
+ int n_syls;
+ gunichar **syls = g_malloc (sizeof (gunichar **));
+
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (length >= 0);
+ g_return_if_fail (analysis != NULL);
+
+ n_chars = n_glyph = g_utf8_strlen (text, length);
+ lvl = pango_x_find_first_subfont (font, &default_charset, 1, &subfont);
+ if (!lvl)
+ {
+ pango_x_fallback_shape (font, glyphs, text, n_chars);
+ return;
+ }
+
+ pango_indic_split_out_characters (&script, text, n_chars, &wc,
+ &n_glyph, glyphs);
+ pango_indic_convert_vowels (&script, FALSE, &n_glyph, wc, FALSE);
+
+ n_syls = 1;
+ syls[0] = wc;
+ sb = glyphs->log_clusters[0];
+ for (i = 0; i < n_glyph; i++)
+ {
+ if (i && (is_consonant (wc[i]) | is_ind_vowel (wc[i]))
+ && wc[i - 1] != VIRAMA)
+ {
+ syls = g_realloc (syls, ((n_syls + 2) * sizeof (gunichar **)));
+ syls[n_syls] = wc + i;
+ n_syls++;
+ sb = glyphs->log_clusters[i];
+ }
+ glyphs->log_clusters[i] = sb;
+ }
+ syls[n_syls] = wc + i;
+
+ for (i = 0; i < n_syls; i++)
+ {
+ pango_indic_shift_vowels (&script, syls[i], syls[i + 1]);
+ }
+
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ while ((i=pango_x_apply_ligatures (font, subfont, &wc, &n_glyph, &glyphs->log_clusters)))
+ {
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ }
+ pango_indic_compact (&script, &n_glyph, wc, glyphs->log_clusters);
+ pango_glyph_string_set_size (glyphs, n_glyph);
+
+ for (i = 0; i < n_glyph; i++)
+ {
+ PangoRectangle logical_rect;
+ glyphs->glyphs[i].glyph = PANGO_X_MAKE_GLYPH (subfont, wc[i]);
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
+ NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
+ }
+ g_free (syls);
+}
+
+static PangoEngine *
+pango_engine_x_new ()
+{
+ PangoEngineShape *result;
+ result = g_new (PangoEngineShape, 1);
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_shape = pango_engine_shape;
+ result->get_coverage = pango_engine_get_coverage;
+ return (PangoEngine *) result;
+}
+
+static void
+pango_engine_break (const char *text,
+ int len,
+ PangoAnalysis * analysis, PangoLogAttr * attrs)
+{
+ const char *cur = text;
+ gint i = 0;
+ gunichar wc;
+
+ while (*cur && cur - text < len)
+ {
+ wc = g_utf8_get_char (cur);
+ if (wc == (gunichar)-1)
+ break; /* FIXME: ERROR */
+
+ attrs[i].is_white = (wc == ' ' || wc == '\t' || wc == 'n') ? 1 : 0;
+ attrs[i].is_break = (i > 0 && attrs[i - 1].is_white) ||
+ attrs[i].is_white;
+ attrs[i].is_char_stop = 1;
+ attrs[i].is_word_stop = (i == 0) || attrs[i - 1].is_white;
+ /* actually, is_word_stop in not correct, but simple and good enough. */
+
+ i++;
+ cur = g_utf8_next_char (cur);
+ }
+}
+
+
+static PangoEngine *
+pango_engine_lang_new ()
+{
+ PangoEngineLang *result;
+
+ result = g_new (PangoEngineLang, 1);
+
+ result->engine.id = SCRIPT_STRING "ScriptEngine";
+ result->engine.type = PANGO_ENGINE_TYPE_LANG;
+ result->engine.length = sizeof (result);
+ result->script_break = pango_engine_break;
+
+ return (PangoEngine *) result;
+}
+
+#ifdef MODULE_PREFIX
+#define MODULE_ENTRY(func) _pango_pango_##func
+#else
+#define MODULE_ENTRY(func) func
+#endif
+
+void
+MODULE_ENTRY(script_engine_list) (PangoEngineInfo ** engines, int *n_engines)
+{
+ *engines = script_engines;
+ *n_engines = n_script_engines;
+}
+
+PangoEngine *
+MODULE_ENTRY(script_engine_load) (const char *id)
+{
+ if (!strcmp (id, SCRIPT_STRING "ScriptEngineLang"))
+ return pango_engine_lang_new ();
+ else if (!strcmp (id, SCRIPT_STRING "ScriptEngineX"))
+ return pango_engine_x_new ();
+ else
+ return NULL;
+}
+
+void
+MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
+{
+}
diff --git a/modules/indic/pango-indic-script.h b/modules/indic/pango-indic-script.h
new file mode 100644
index 00000000..90c69eca
--- /dev/null
+++ b/modules/indic/pango-indic-script.h
@@ -0,0 +1,40 @@
+#ifndef __INDIC_SCRIPT__
+#define __INDIC_SCRIPT__
+
+#define RANGE_END (RANGE_START + RANGE_SIZE - 1)
+
+#ifdef ISCII_BASED
+#define VIRAMA (0x4d + RANGE_START)
+#define CANDRA (0x01 + RANGE_START)
+#define ANUSWAR (0x02 + RANGE_START)
+#define NUKTA (0x3c + RANGE_START)
+#define RA (0x30 + RANGE_START)
+#endif
+
+#define SCRIPT_ENGINE_DEFINITION \
+ static PangoEngineInfo script_engines[] = \
+ { \
+ { \
+ SCRIPT_STRING "ScriptEngineLang", \
+ PANGO_ENGINE_TYPE_LANG, \
+ PANGO_RENDER_TYPE_NONE, \
+ pango_indic_range, G_N_ELEMENTS (pango_indic_range)}, \
+ { \
+ SCRIPT_STRING "ScriptEngineX", \
+ PANGO_ENGINE_TYPE_SHAPE, \
+ PANGO_RENDER_TYPE_X, \
+ pango_indic_range, G_N_ELEMENTS (pango_indic_range)} \
+ }; \
+ static gint n_script_engines = G_N_ELEMENTS (script_engines);
+
+inline gunichar
+pango_indic_get_char (gunichar * chars,
+ gunichar * end)
+{
+ if (chars >= end)
+ return 0;
+ return *chars;
+}
+
+
+#endif