diff options
author | Robert Brady <rbrady@src.gnome.org> | 2000-11-08 06:07:47 +0000 |
---|---|---|
committer | Robert Brady <rbrady@src.gnome.org> | 2000-11-08 06:07:47 +0000 |
commit | 452359df74d9ab351b010a58693e597a53aa6362 (patch) | |
tree | 0011ec5c2192c96d27663cdd2a945a784f8920de /modules | |
parent | 28b8f5db1a22d8ccefb4a88bb0f16ea3d84afade (diff) | |
download | pango-452359df74d9ab351b010a58693e597a53aa6362.tar.gz |
Shiny new Indic shapers!
Diffstat (limited to 'modules')
-rw-r--r-- | modules/Makefile.am | 2 | ||||
-rw-r--r-- | modules/devanagari/Makefile.am | 21 | ||||
-rw-r--r-- | modules/devanagari/dev-ligatures.h | 49 | ||||
-rw-r--r-- | modules/devanagari/devanagari.c | 615 | ||||
-rw-r--r-- | modules/indic/.cvsignore | 6 | ||||
-rw-r--r-- | modules/indic/Makefile.am | 61 | ||||
-rw-r--r-- | modules/indic/bengali-x.c | 359 | ||||
-rw-r--r-- | modules/indic/bengali.c | 359 | ||||
-rw-r--r-- | modules/indic/devanagari-x.c | 411 | ||||
-rw-r--r-- | modules/indic/devanagari.c | 411 | ||||
-rw-r--r-- | modules/indic/gujarati-x.c | 387 | ||||
-rw-r--r-- | modules/indic/gujarati.c | 387 | ||||
-rw-r--r-- | modules/indic/gurmukhi-x.c | 301 | ||||
-rw-r--r-- | modules/indic/gurmukhi.c | 301 | ||||
-rw-r--r-- | modules/indic/myanmar-x.c | 281 | ||||
-rw-r--r-- | modules/indic/myanmar.c | 281 | ||||
-rw-r--r-- | modules/indic/pango-indic-script.h | 40 |
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 |