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