summaryrefslogtreecommitdiff
path: root/modules
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
parent28b8f5db1a22d8ccefb4a88bb0f16ea3d84afade (diff)
downloadpango-452359df74d9ab351b010a58693e597a53aa6362.tar.gz
Shiny new Indic shapers!
Diffstat (limited to 'modules')
-rw-r--r--modules/Makefile.am2
-rw-r--r--modules/devanagari/Makefile.am21
-rw-r--r--modules/devanagari/dev-ligatures.h49
-rw-r--r--modules/devanagari/devanagari.c615
-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
17 files changed, 3586 insertions, 686 deletions
diff --git a/modules/Makefile.am b/modules/Makefile.am
index 80092322..3647c502 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -2,9 +2,9 @@
SUBDIRS = \
arabic \
- devanagari \
basic \
hangul \
+ indic \
tamil \
thai
diff --git a/modules/devanagari/Makefile.am b/modules/devanagari/Makefile.am
deleted file mode 100644
index b050c95d..00000000
--- a/modules/devanagari/Makefile.am
+++ /dev/null
@@ -1,21 +0,0 @@
-## Process this file with automake to create Makefile.in.
-
-sources = \
- devanagari.c \
- dev-ligatures.h
-
-if INCLUDE_DEVANAGARI
-noinst_LTLIBRARIES = libpango-devanagari.la
-moddefine = -DMODULE_PREFIX
-else
-moduledir = $(libdir)/pango/modules
-module_LTLIBRARIES = pango-devanagari.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 = $(sources)
-
-libpango_devanagari_la_SOURCES = $(sources)
-
diff --git a/modules/devanagari/dev-ligatures.h b/modules/devanagari/dev-ligatures.h
deleted file mode 100644
index fff44ba7..00000000
--- a/modules/devanagari/dev-ligatures.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* ones marked with ! weren't used by CURender.java. The
- mappings were worked out by staring at the Unicode code
- charts for a long time.
- */
-
-{ 0xE900, { 0x0915, VIRAMA, 0x0937 } },
-{ 0xE901, { 0x091C, VIRAMA, 0x091E } },
-{ 0xE902, { 0x0924, VIRAMA, 0x0924 } },
-{ 0xE903, { 0x0924, VIRAMA, 0x0930 } },
-{ 0xE904, { 0x0936, VIRAMA, 0x091B } },
-{ 0xE905, { 0x0936, VIRAMA, 0x0930 } },
-{ 0xE906, { 0x0936, VIRAMA, 0x0935 } },
-
-{ 0xE907, { 0x0915, VIRAMA, RA } },
-{ 0xE908, { 0x091C, VIRAMA, RA } },
-{ 0xE909, { 0x095B, VIRAMA, RA } },
-{ 0xE90A, { 0x092B, VIRAMA, RA } },
-{ 0xE90B, { 0x095E, VIRAMA, RA } },
-{ 0xE90C, { 0x092A, VIRAMA, RA } },
-{ 0xE90D, { 0x0938, VIRAMA, RA } },
-
-{ 0xE940, { 0x0915, VIRAMA, 0x0915 } },
-{ 0xE941, { 0x0915, VIRAMA, 0x0924 } },
-{ 0xE942, { 0x0919, VIRAMA, 0x0915 } }, /* ! */
-{ 0xE943, { 0x0919, VIRAMA, 0x0916 } }, /* ! */
-{ 0xE944, { 0x0919, VIRAMA, 0x0917 } }, /* ! */
-{ 0xE945, { 0x0919, VIRAMA, 0x0918 } }, /* ! */
-{ 0xE946, { 0x091e, VIRAMA, 0x091e } }, /* ! */
-{ 0xE947, { 0x0926, VIRAMA, 0x0918 } },
-{ 0xE948, { 0x0926, VIRAMA, 0x0926 } }, /* ! */
-{ 0xE949, { 0x0926, VIRAMA, 0x0927 } },
-{ 0xE94A, { 0x0926, VIRAMA, 0x0937 } }, /* ! */
-{ 0xE94B, { 0x0926, VIRAMA, 0x092D } }, /* ! */
-{ 0xE94C, { 0x0926, VIRAMA, 0x092E } }, /* ! */
-{ 0xE94D, { 0x0926, VIRAMA, 0x092F } },
-{ 0xE94E, { 0x0926, VIRAMA, 0x0935 } },
-{ 0xE94F, { 0x091F, VIRAMA, 0x091F } },
-{ 0xE950, { 0x091F, VIRAMA, 0x0920 } },
-{ 0xE951, { 0x0920, VIRAMA, 0x0920 } }, /* ! */
-{ 0xE952, { 0x0921, VIRAMA, 0x0917 } },
-{ 0xE953, { 0x0921, VIRAMA, 0x0921 } }, /* ! */
-{ 0xE954, { 0x0921, VIRAMA, 0x0922 } }, /* ! */
-{ 0xE955, { 0x0928, VIRAMA, 0x0928 } },
-{ 0xE956, { 0x0939, VIRAMA, 0x092e } }, /* ! */
-{ 0xE957, { 0x0939, VIRAMA, 0x092f } }, /* ! */
-{ 0xE958, { 0x0939, VIRAMA, 0x0932 } }, /* ! */
-{ 0xE959, { 0x0939, VIRAMA, 0x0935 } }, /* ! */
-/* { 0xE95a, { 0x0939, VIRAMA, 0x0e903 } }, ! */
-
diff --git a/modules/devanagari/devanagari.c b/modules/devanagari/devanagari.c
deleted file mode 100644
index 7f3c1528..00000000
--- a/modules/devanagari/devanagari.c
+++ /dev/null
@@ -1,615 +0,0 @@
-/* Pango - Devanagari module
- * devanagari.c:
- *
- * Copyright (C) 2000 Robert Brady <rwb197@zepler.org>
- *
- * 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 <glib.h>
-#include <stdio.h>
-
-#include "pango.h"
-#include "pangox.h"
-
-#define VIRAMA 0x94d
-#define CANDRA 0x901
-#define ANUSWAR 0x902
-#define NUKTA 0x93c
-#define RA 0x930
-#define JOINING_RA 0xe97f
-#define REPHA 0xe97e
-#define EYELASH_RA 0xe97d
-#define RRA 0x931
-
-#define U_S 0x941
-#define UU_S 0x942
-
-typedef struct _LigData LigData;
-
-struct _LigData
- {
- int replacement;
- int source[3];
- };
-
-static LigData ligatures[] =
-{
-#include "dev-ligatures.h"
-};
-
-static gint n_ligatures = G_N_ELEMENTS (ligatures);
-
-static char *default_charset[] =
-{
- "iso10646-dev",
- /* devanagari encoded in iso10646 way, with PUA used for
- * ligatures and half forms */
-};
-
-/* Table about ligatures in the font. This should come from the font
- * somehow : this needs to be co-ordinated with fonts@xfree86.org.
- * (and for whatever passes for a font working group at X.org)
- */
-
-static PangoEngineRange devanagari_range[] =
-{
- {0x900, 0x97f, "*"}
-};
-
-static PangoEngineInfo script_engines[] =
-{
- {
- "DevanagariScriptEngineLang",
- PANGO_ENGINE_TYPE_LANG,
- PANGO_RENDER_TYPE_NONE,
- devanagari_range, G_N_ELEMENTS (devanagari_range)},
- {
- "DevanagariScriptEngineX",
- PANGO_ENGINE_TYPE_SHAPE,
- PANGO_RENDER_TYPE_X,
- devanagari_range, G_N_ELEMENTS (devanagari_range)}
-};
-
-static gint n_script_engines = G_N_ELEMENTS (script_engines);
-
-static gboolean
- find_unic_font (PangoFont * font, char *charsets[], PangoXSubfont * rfont);
-
-static PangoCoverage *
-devanagari_engine_get_coverage (PangoFont * font, const char *lang)
-{
- gunichar i;
- PangoCoverage *result = pango_coverage_new ();
- PangoXSubfont subfont;
-
- int dev_font = find_unic_font (font, default_charset, &subfont);
-
- if (dev_font)
- {
- for (i = 0x900; i < 0x97f; i++)
- pango_coverage_set (result, i, PANGO_COVERAGE_EXACT);
- }
-
- return result;
-}
-
-static gboolean
-find_unic_font (PangoFont * font, char *charsets[], PangoXSubfont * rfont)
-{
- int n_subfonts;
- int result = 0;
- PangoXSubfont *subfonts;
- int *subfont_charsets;
- n_subfonts = pango_x_list_subfonts (font, charsets, 1,
- &subfonts, &subfont_charsets);
-
- if (n_subfonts > 0)
- {
- rfont[0] = subfonts[0];
- result = 1;
- }
-
- g_free (subfonts);
- g_free (subfont_charsets);
- return result;
-}
-
-static int
-is_ligating_consonant (int ch)
-{
- /* false for 958 to 961, as these don't ligate in any way */
- return (ch >= 0x915 && ch <= 0x939);
-}
-
-static int
-is_comb_vowel (int i)
-{
- /* one that combines, whether or not it spaces */
- return (i >= 0x93E && i <= 0x94c) || (i >= 0x962 && i <= 0x963);
-}
-
-static int
-vowelsign_to_letter (int i)
-{
- if (i >= 0x93e && i <= 0x94c)
- return i - 0x93e + 0x906;
- return i;
-}
-
-static int
-is_half_consonant (int i)
-{
- return (i >= 0xe915 && i <= 0xe939) || (i >= 0xe970 && i <= 0xe976);
-}
-
-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 int
-is_nonspacing_vowel (gunichar c)
-{
- /* one that doesn't space. ie 93f and 940 don't count */
- return (c >= 0x941 && c <= 0x948) || (c >= 0x962 && c <= 0x963);
-}
-
-static int
-get_char (gunichar * chars, gunichar * end)
-{
- if (chars >= end)
- return 0;
- return *chars;
-}
-
-static void
-devanagari_shift_vowels (gunichar * chars, gunichar * end)
-{
- /* moves 0x93f (I) before consonant clusters where appropriate. */
- gunichar *strt = chars;
- while (chars < end)
- {
- if (*chars == 0x93f && chars > strt)
- {
- gunichar *bubble = chars;
- int i = 1;
-
- /* move back TO START! */
-
- while (bubble > strt)
- {
- bubble[0] = bubble[-1];
- bubble[-1] = 0x93f;
- i = 0;
- bubble--;
- }
- }
- chars++;
- }
-}
-
-void
-devanagari_convert_vowels (int *num, gunichar * chars)
-{
- /* goes along and converts matras to vowel letters if needed.
- * this is only currently done at the beginning of the string. */
- gunichar *end = chars + *num;
- gunichar *start = chars;
- while (chars < end)
- {
- if ((chars == start && is_comb_vowel (chars[0])) ||
- (chars != start && is_comb_vowel (chars[0])
- && is_comb_vowel (chars[-1])))
- {
- chars[0] = vowelsign_to_letter (chars[0]);
- }
- chars++;
- }
-}
-
-static void
-devanagari_compact (int *num, gunichar * chars, gint * cluster)
-{
- /* shuffle stuff up into the blanked out elements. */
- gunichar *dest = chars;
- gunichar *end = chars + *num;
- gint *cluster_dest = cluster;
- while (chars < end)
- {
- if (*chars)
- {
- *dest = *chars;
- *cluster_dest = *cluster;
- dest++;
- chars++;
- cluster++;
- cluster_dest++;
- }
- else
- {
- chars++;
- cluster++;
- }
- }
- *num -= (chars - dest);
-}
-
-#if 0
-const char *foo[] =
-{
- "k", "kh", "g", "gh", "ng",
- "c", "ch", "j", "jh", "ny",
- "tt", "tth", "dd", "ddh", "nn",
- "t", "th", "d", "dh", "n", "nnn",
- "p", "ph", "b", "bh", "m",
-
- "y", "r", "rr", "l", "ll", "lll",
-
- "v", "sh", "ss", "s", "h",
-
- "-", "-", "-", "-",
-
- "aa",
- "i", "ii",
- "u", "uu",
- "[r]", "[rr]",
- "[e]", "{e}",
- "e", "ai",
- "[o]", "{o}",
- "o", "au",
-};
-
-const char *bar[] =
-{
- "A", "AA",
- "I", "II",
- "U", "UU",
- "[R]", "[RR]",
- "[E]", "{E}",
- "E", "AI",
- "[O]", "{O}",
- "O", "AU",
-};
-#endif
-
-static void
-devanagari_make_ligs (gunichar * start, gunichar * end, int *cluster)
-{
- gunichar t0 = get_char (start, end);
- gunichar t1 = get_char (start + 1, end);
- gunichar t2 = get_char (start + 2, end);
- gunichar t3 = get_char (start + 3, end);
-
- int i, j;
- int repha = 0, ligature = 0;
-
- for (i = 0; i < (end - start); i++)
- {
- t0 = get_char (start + i, end);
- t1 = get_char (start + 1 + i, end);
- t2 = get_char (start + 2 + i, end);
- t3 = get_char (start + 3 + i, end);
-
- if (!ligature)
- {
- for (j = 0; j < n_ligatures; j++)
- {
- /* handle the conjuncts */
- LigData *l = ligatures + j;
- if (t0 == l->source[0] && t1 == l->source[1]
- && t2 == l->source[2])
- {
- start[i + 0] = 0;
- start[i + 1] = 0;
- start[i + 2] = l->replacement;
- ligature = 1;
- break;
- }
- }
- if (j != n_ligatures)
- continue;
- }
-
- if ((t0 >= 0xe900 && t0 <= 0xe906) && t1 == VIRAMA
- && is_ligating_consonant (t2))
- {
- start[i + 1] = start[i] + 0x70;
- start[i] = 0;
- continue;
- }
-
- if (is_consonant (t0) && t1 == VIRAMA && t2 == RA)
- {
- start[i + 1] = 0;
- start[i + 2] = JOINING_RA;
- continue;
- }
-
- if (t0 == RRA && t1 == VIRAMA)
- {
- start[i] = 0;
- start[i + 1] = EYELASH_RA;
- continue;
- }
-
- if (t0 == RA && t1 == VIRAMA && is_ligating_consonant (t2))
- {
-
- start[i + 0] = 0;
- start[i + 1] = 0;
- start[i + 2] = t2;
- repha = 1;
- continue;
- }
-
- if (is_ligating_consonant (t0) &&
- t1 == VIRAMA && is_ligating_consonant (t2))
- {
- start[i + 0] = t0 + 0xe000;
- start[i + 1] = 0;
- start[i + 2] = t2;
- continue;
- }
-
- if (t0 == RA && (t1 == U_S || t1 == UU_S))
- {
-
- if (t1 == U_S)
- start[i + 1] = 0xe90e;
-
- if (t1 == UU_S)
- start[i + 1] = 0xe90f;
-
- start[i] = 0;
-
- }
- }
-
- for (i = 0; i < (end - start); i++)
- {
- t0 = get_char (start + i, end);
- t1 = get_char (start + 1 + i, end);
- t2 = get_char (start + 2 + i, end);
- t3 = get_char (start + 3 + i, end);
- }
-
- if (repha)
- {
- int src = 0, dest = 0;
- while (src < (end - start))
- {
- start[dest] = start[src];
- src++;
- if (start[dest])
- dest++;
- }
- while (dest < (end - start))
- {
- start[dest] = 0;
- dest++;
- }
- end[-1] = REPHA;
- }
-}
-
-static void
-devanagari_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 = find_unic_font (font, default_charset, &subfont);
- if (!lvl)
- {
- PangoGlyph unknown_glyph = pango_x_get_unknown_glyph (font);
- PangoRectangle logical_rect;
- pango_font_get_glyph_extents (font, unknown_glyph, NULL, &logical_rect);
- pango_glyph_string_set_size (glyphs, n_chars);
- p = text;
- for (i = 0; i < n_chars; i++)
- {
- glyphs->glyphs[i].glyph = unknown_glyph;
- glyphs->glyphs[i].geometry.x_offset = 0;
- glyphs->glyphs[i].geometry.y_offset = 0;
- glyphs->glyphs[i].geometry.width = logical_rect.width;
- glyphs->log_clusters[i] = 0;
-
- p = g_utf8_next_char (p);
- }
- return;
- }
- p = text;
- wc = (gunichar *) g_malloc (sizeof (gunichar) * n_chars);
- pango_glyph_string_set_size (glyphs, n_glyph);
- for (i = 0; i < n_chars; i++)
- {
- wc[i] = g_utf8_get_char (p);
- glyphs->log_clusters[i] = p - text;
- p = g_utf8_next_char (p);
- }
-
- devanagari_convert_vowels (&n_glyph, wc);
-
- 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] != 0x94d)
- {
- 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++)
- {
- devanagari_make_ligs (syls[i], syls[i + 1], glyphs->log_clusters +
- (syls[i] - wc));
- devanagari_shift_vowels (syls[i], syls[i + 1]);
- }
-
- devanagari_compact (&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;
-
- if (wc[i] == JOINING_RA || wc[i] == ANUSWAR ||
- wc[i] == REPHA || wc[i] == VIRAMA || wc[i] == CANDRA ||
- is_nonspacing_vowel (wc[i]))
- {
- if (wc[i] == VIRAMA)
- {
- glyphs->glyphs[i].geometry.x_offset =
- (-glyphs->glyphs[i - 1].geometry.width / 2);
-
- if (!glyphs->glyphs[i].geometry.x_offset)
- glyphs->glyphs[i].geometry.x_offset =
- (-glyphs->glyphs[i - 2].geometry.width / 2);
- }
- else
- glyphs->glyphs[i].geometry.x_offset = -logical_rect.width * 2;
-
- glyphs->glyphs[i].geometry.width = 0;
- glyphs->log_clusters[i] = glyphs->log_clusters[i - 1];
- }
- }
- g_free (syls);
-}
-
-static PangoEngine *
-devanagari_engine_x_new ()
-{
- PangoEngineShape *result;
- result = g_new (PangoEngineShape, 1);
- result->engine.id = "DevanagariScriptEngine";
- result->engine.type = PANGO_ENGINE_TYPE_LANG;
- result->engine.length = sizeof (result);
- result->script_shape = devanagari_engine_shape;
- result->get_coverage = devanagari_engine_get_coverage;
- return (PangoEngine *) result;
-}
-
-static void
-devanagari_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 *
-devanagari_engine_lang_new ()
-{
- PangoEngineLang *result;
-
- result = g_new (PangoEngineLang, 1);
-
- result->engine.id = "DevanagariScriptEngine";
- result->engine.type = PANGO_ENGINE_TYPE_LANG;
- result->engine.length = sizeof (result);
- result->script_break = devanagari_engine_break;
-
- return (PangoEngine *) result;
-}
-
-#ifdef MODULE_PREFIX
-#define MODULE_ENTRY(func) _pango_devanagari_##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, "DevanagariScriptEngineLang"))
- return devanagari_engine_lang_new ();
- else if (!strcmp (id, "DevanagariScriptEngineX"))
- return devanagari_engine_x_new ();
- else
- return NULL;
-}
-
-void
-MODULE_ENTRY(script_engine_unload) (PangoEngine * engine)
-{
-}
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