From 5aea38b87e7237795178c9455d5e825e2f9507dd Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Mon, 8 May 2000 15:50:13 +0000 Subject: Add a simple Thai shaper. (Reasonably complete but intended mostly for an Mon May 8 16:19:22 2000 Owen Taylor * modules/thai/* modules/Makefile.am configure.in: Add a simple Thai shaper. (Reasonably complete but intended mostly for an example for the shape docs right now.) * pango/pangox.h (PANGO_X_GLYPH_INDEX): Protect arguments to macros. --- ChangeLog | 12 +- ChangeLog.pre-1-0 | 12 +- ChangeLog.pre-1-10 | 12 +- ChangeLog.pre-1-2 | 12 +- ChangeLog.pre-1-4 | 12 +- ChangeLog.pre-1-6 | 12 +- ChangeLog.pre-1-8 | 12 +- configure.in | 4 +- examples/viewer.c | 2 +- modules/Makefile.am | 3 +- modules/thai/.cvsignore | 6 + modules/thai/Makefile.am | 20 +++ modules/thai/thai-x.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++ modules/thai/thai.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++ pango/pangox.h | 6 +- 15 files changed, 968 insertions(+), 13 deletions(-) create mode 100644 modules/thai/.cvsignore create mode 100644 modules/thai/Makefile.am create mode 100644 modules/thai/thai-x.c create mode 100644 modules/thai/thai.c diff --git a/ChangeLog b/ChangeLog index 8a23fa5c..4b7c8afb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,14 @@ -Sun May 7 00:00:00 2000 Owen Taylor +Mon May 8 16:19:22 2000 Owen Taylor + + * modules/thai/* modules/Makefile.am configure.in: + Add a simple Thai shaper. (Reasonably complete but + intended mostly for an example for the shape docs + right now.) + + * pango/pangox.h (PANGO_X_GLYPH_INDEX): Protect + arguments to macros. + +Sun May 7 06:15:34 2000 Owen Taylor * modules/basic/basic.c (basic_engine_shape): When handling overstrikes, try to guess a bit better diff --git a/ChangeLog.pre-1-0 b/ChangeLog.pre-1-0 index 8a23fa5c..4b7c8afb 100644 --- a/ChangeLog.pre-1-0 +++ b/ChangeLog.pre-1-0 @@ -1,4 +1,14 @@ -Sun May 7 00:00:00 2000 Owen Taylor +Mon May 8 16:19:22 2000 Owen Taylor + + * modules/thai/* modules/Makefile.am configure.in: + Add a simple Thai shaper. (Reasonably complete but + intended mostly for an example for the shape docs + right now.) + + * pango/pangox.h (PANGO_X_GLYPH_INDEX): Protect + arguments to macros. + +Sun May 7 06:15:34 2000 Owen Taylor * modules/basic/basic.c (basic_engine_shape): When handling overstrikes, try to guess a bit better diff --git a/ChangeLog.pre-1-10 b/ChangeLog.pre-1-10 index 8a23fa5c..4b7c8afb 100644 --- a/ChangeLog.pre-1-10 +++ b/ChangeLog.pre-1-10 @@ -1,4 +1,14 @@ -Sun May 7 00:00:00 2000 Owen Taylor +Mon May 8 16:19:22 2000 Owen Taylor + + * modules/thai/* modules/Makefile.am configure.in: + Add a simple Thai shaper. (Reasonably complete but + intended mostly for an example for the shape docs + right now.) + + * pango/pangox.h (PANGO_X_GLYPH_INDEX): Protect + arguments to macros. + +Sun May 7 06:15:34 2000 Owen Taylor * modules/basic/basic.c (basic_engine_shape): When handling overstrikes, try to guess a bit better diff --git a/ChangeLog.pre-1-2 b/ChangeLog.pre-1-2 index 8a23fa5c..4b7c8afb 100644 --- a/ChangeLog.pre-1-2 +++ b/ChangeLog.pre-1-2 @@ -1,4 +1,14 @@ -Sun May 7 00:00:00 2000 Owen Taylor +Mon May 8 16:19:22 2000 Owen Taylor + + * modules/thai/* modules/Makefile.am configure.in: + Add a simple Thai shaper. (Reasonably complete but + intended mostly for an example for the shape docs + right now.) + + * pango/pangox.h (PANGO_X_GLYPH_INDEX): Protect + arguments to macros. + +Sun May 7 06:15:34 2000 Owen Taylor * modules/basic/basic.c (basic_engine_shape): When handling overstrikes, try to guess a bit better diff --git a/ChangeLog.pre-1-4 b/ChangeLog.pre-1-4 index 8a23fa5c..4b7c8afb 100644 --- a/ChangeLog.pre-1-4 +++ b/ChangeLog.pre-1-4 @@ -1,4 +1,14 @@ -Sun May 7 00:00:00 2000 Owen Taylor +Mon May 8 16:19:22 2000 Owen Taylor + + * modules/thai/* modules/Makefile.am configure.in: + Add a simple Thai shaper. (Reasonably complete but + intended mostly for an example for the shape docs + right now.) + + * pango/pangox.h (PANGO_X_GLYPH_INDEX): Protect + arguments to macros. + +Sun May 7 06:15:34 2000 Owen Taylor * modules/basic/basic.c (basic_engine_shape): When handling overstrikes, try to guess a bit better diff --git a/ChangeLog.pre-1-6 b/ChangeLog.pre-1-6 index 8a23fa5c..4b7c8afb 100644 --- a/ChangeLog.pre-1-6 +++ b/ChangeLog.pre-1-6 @@ -1,4 +1,14 @@ -Sun May 7 00:00:00 2000 Owen Taylor +Mon May 8 16:19:22 2000 Owen Taylor + + * modules/thai/* modules/Makefile.am configure.in: + Add a simple Thai shaper. (Reasonably complete but + intended mostly for an example for the shape docs + right now.) + + * pango/pangox.h (PANGO_X_GLYPH_INDEX): Protect + arguments to macros. + +Sun May 7 06:15:34 2000 Owen Taylor * modules/basic/basic.c (basic_engine_shape): When handling overstrikes, try to guess a bit better diff --git a/ChangeLog.pre-1-8 b/ChangeLog.pre-1-8 index 8a23fa5c..4b7c8afb 100644 --- a/ChangeLog.pre-1-8 +++ b/ChangeLog.pre-1-8 @@ -1,4 +1,14 @@ -Sun May 7 00:00:00 2000 Owen Taylor +Mon May 8 16:19:22 2000 Owen Taylor + + * modules/thai/* modules/Makefile.am configure.in: + Add a simple Thai shaper. (Reasonably complete but + intended mostly for an example for the shape docs + right now.) + + * pango/pangox.h (PANGO_X_GLYPH_INDEX): Protect + arguments to macros. + +Sun May 7 06:15:34 2000 Owen Taylor * modules/basic/basic.c (basic_engine_shape): When handling overstrikes, try to guess a bit better diff --git a/configure.in b/configure.in index 655bfaa2..e915e250 100644 --- a/configure.in +++ b/configure.in @@ -112,7 +112,7 @@ if ! test "x$with_included_modules" = xno || test "x$with_included_modules" = x # If no modules specified, include all modules if test "x$with_included_modules" = xyes ; then - included_modules="arabic,devanagari,basic,hangul,tamil" + included_modules="arabic,devanagari,basic,hangul,tamil,thai" else included_modules="$with_included_modules" fi @@ -132,6 +132,7 @@ AM_CONDITIONAL(INCLUDE_BASIC,echo $included_modules | grep '\(^\|,\)basic\($\|,\ AM_CONDITIONAL(INCLUDE_DEVANAGARI,echo $included_modules | grep '\(^\|,\)devanagari\($\|,\)' > /dev/null) AM_CONDITIONAL(INCLUDE_HANGUL,echo $included_modules | grep '\(^\|,\)hangul\($\|,\)' > /dev/null) AM_CONDITIONAL(INCLUDE_TAMIL,echo $included_modules | grep '\(^\|,\)tamil\($\|,\)' > /dev/null) +AM_CONDITIONAL(INCLUDE_THAI,echo $included_modules | grep '\(^\|,\)thai\($\|,\)' > /dev/null) # # We use flockfile to implement pango_getline() - should be moved to GLib @@ -191,6 +192,7 @@ modules/basic/Makefile modules/devanagari/Makefile modules/hangul/Makefile modules/tamil/Makefile +modules/thai/Makefile examples/Makefile docs/Makefile tools/Makefile diff --git a/examples/viewer.c b/examples/viewer.c index 61beceab..cbc060a6 100644 --- a/examples/viewer.c +++ b/examples/viewer.c @@ -372,7 +372,7 @@ button_press (GtkWidget *layout, GdkEventButton *event) static void checkbutton_toggled (GtkWidget *widget, gpointer data) { - GSList *para_list; + GList *para_list; pango_context_set_base_dir (context, GTK_TOGGLE_BUTTON (widget)->active ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR); diff --git a/modules/Makefile.am b/modules/Makefile.am index 90cb1513..e2ba627f 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -5,7 +5,8 @@ SUBDIRS = \ devanagari \ basic \ hangul \ - tamil + tamil \ + thai install-data-local: $(mkinstalldirs) $(DESTDIR)$(localstatedir)/lib/pango diff --git a/modules/thai/.cvsignore b/modules/thai/.cvsignore new file mode 100644 index 00000000..6e5ca7ed --- /dev/null +++ b/modules/thai/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +.deps +.libs +*.lo +*.la diff --git a/modules/thai/Makefile.am b/modules/thai/Makefile.am new file mode 100644 index 00000000..38d4fc0e --- /dev/null +++ b/modules/thai/Makefile.am @@ -0,0 +1,20 @@ +## Process this file with automake to create Makefile.in. + +sources = thai.c + +if INCLUDE_THAI +noinst_LTLIBRARIES = libpango-thai.la +moddefine = -DMODULE_PREFIX +else +moduledir = $(libdir)/pango/modules +module_LTLIBRARIES = pango-thai.la +endif + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/pango/ $(moddefine) + +pango_thai_la_LDFLAGS = -rpath $(libdir) -export-dynamic -avoid-version -module +pango_thai_la_LIBADD = $(UNICODE_LIBS) +pango_thai_la_SOURCES = $(sources) + +libpango_thai_la_SOURCES = $(sources) + diff --git a/modules/thai/thai-x.c b/modules/thai/thai-x.c new file mode 100644 index 00000000..17d1d024 --- /dev/null +++ b/modules/thai/thai-x.c @@ -0,0 +1,428 @@ +/* Pango + * thai.c: + * + * Copyright (C) 1999 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include +#include "pango.h" +#include "pangox.h" +#include "utils.h" +#include +#include + +/* We handle the range U+0e01 to U+0e5b exactly + */ +static PangoEngineRange thai_ranges[] = { + { 0x0e01, 0x0e5b, "*" }, /* Thai */ +}; + +static PangoEngineInfo script_engines[] = { + { + "ThaiScriptEngineLang", + PANGO_ENGINE_TYPE_LANG, + PANGO_RENDER_TYPE_NONE, + thai_ranges, G_N_ELEMENTS(thai_ranges) + }, + { + "ThaiScriptEngineX", + PANGO_ENGINE_TYPE_SHAPE, + PANGO_RENDER_TYPE_X, + thai_ranges, G_N_ELEMENTS(thai_ranges) + } +}; + +/* + * Language script engine + */ + +static void +thai_engine_break (const char *text, + gint len, + PangoAnalysis *analysis, + PangoLogAttr *attrs) +{ +} + +static PangoEngine * +thai_engine_lang_new () +{ + PangoEngineLang *result; + + result = g_new (PangoEngineLang, 1); + + result->engine.id = "ThaiScriptEngine"; + result->engine.type = PANGO_ENGINE_TYPE_LANG; + result->engine.length = sizeof (result); + result->script_break = thai_engine_break; + + return (PangoEngine *)result; +} + +/* + * X window system script engine portion + */ + +typedef struct _ThaiFontInfo ThaiFontInfo; + +/* The type of encoding that we will use + */ +typedef enum { + THAI_FONT_NONE, + THAI_FONT_XTIS, + THAI_FONT_TIS, + THAI_FONT_ISO10646 +} ThaiFontType; + +struct _ThaiFontInfo +{ + PangoFont *font; + ThaiFontType type; + PangoXSubfont subfont; +}; + +/* All combining marks for Thai fall in the range U+0E30-U+0E50, + * so we confine our data tables to that range, and use + * default values for characters outside those ranges. + */ + +/* Map from code point to group used for rendering with XTIS fonts + * (0 == base character) + */ +static const char groups[32] = { + 0, 1, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 1, 0 +}; + +/* Map from code point to index within group 1 + * (0 == no combining mark from group 1) + */ +static const char group1_map[32] = { + 0, 1, 0, 0, 2, 3, 4, 5, + 6, 7, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Map from code point to index within group 2 + * (0 == no combining mark from group 2) + */ +static const char group2_map[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 1, 0 +}; + +/* Returns a structure with information we will use to rendering given the + * #PangoFont. This is computed once per font and cached for later retrieval. + */ +static ThaiFontInfo * +get_font_info (PangoFont *font) +{ + static const char *charsets[] = { + "xtis620.2529-1", + "xtis-0", + "tis620.2529-1", + "iso10646-1", + }; + + static const int charset_types[] = { + THAI_FONT_XTIS, + THAI_FONT_XTIS, + THAI_FONT_TIS, + THAI_FONT_ISO10646 + }; + + ThaiFontInfo *font_info; + + font_info = pango_font_get_data (font, "thai-font-info"); + if (!font_info) + { + /* No cached information not found, so we need to compute it + * from scratch + */ + PangoXSubfont *subfont_ids; + int *subfont_charsets; + int n_subfonts, i; + + font_info = g_new (ThaiFontInfo, 1); + font_info->font = font; + font_info->type = THAI_FONT_NONE; + + pango_font_set_data (font, "thai-font-info", font_info, (GDestroyNotify)g_free); + + n_subfonts = pango_x_list_subfonts (font, (char **)charsets, G_N_ELEMENTS (charsets), + &subfont_ids, &subfont_charsets); + + for (i=0; i < n_subfonts; i++) + { + ThaiFontType font_type = charset_types[subfont_charsets[i]]; + + if (font_type != THAI_FONT_ISO10646 || + pango_x_has_glyph (font, PANGO_X_MAKE_GLYPH (subfont_ids[i], 0xe01))) + { + font_info->type = font_type; + font_info->subfont = subfont_ids[i]; + + break; + } + } + + g_free (subfont_ids); + g_free (subfont_charsets); + } + + return font_info; +} + +static void +add_glyph (ThaiFontInfo *font_info, + PangoGlyphString *glyphs, + int cluster_start, + PangoGlyph glyph, + gboolean combining) +{ + PangoRectangle ink_rect, logical_rect; + int index = glyphs->num_glyphs; + + pango_glyph_string_set_size (glyphs, index + 1); + + glyphs->glyphs[index].glyph = glyph; + glyphs->glyphs[index].attr.is_cluster_start = combining ? 0 : 1; + + glyphs->log_clusters[index] = cluster_start; + + pango_font_get_glyph_extents (font_info->font, + glyphs->glyphs[index].glyph, &ink_rect, &logical_rect); + + if (combining) + { + glyphs->glyphs[index].geometry.width = + MAX (logical_rect.width, glyphs->glyphs[index - 1].geometry.width); + glyphs->glyphs[index - 1].geometry.width = 0; + glyphs->glyphs[index].geometry.x_offset = 0; + } + else + { + glyphs->glyphs[index].geometry.x_offset = 0; + glyphs->glyphs[index].geometry.width = logical_rect.width; + } + + glyphs->glyphs[index].geometry.y_offset = 0; +} + +/* Return the glyph code within the font for the given Unicode Thai + * code pointer + */ +static int +get_glyph (ThaiFontInfo *font_info, unicode_char_t wc) +{ + switch (font_info->type) + { + case THAI_FONT_NONE: + return pango_x_get_unknown_glyph (font_info->font); + case THAI_FONT_XTIS: + return PANGO_X_MAKE_GLYPH (font_info->subfont, 0x100 * (wc - 0xe00 + 0x20) + 0x30); + case THAI_FONT_TIS: + return PANGO_X_MAKE_GLYPH (font_info->subfont, wc - 0xe00 + 0xA0); + case THAI_FONT_ISO10646: + return PANGO_X_MAKE_GLYPH (font_info->subfont, wc); + } + return 0; /* Quiet GCC */ +} + +static void +add_cluster (ThaiFontInfo *font_info, + PangoGlyphString *glyphs, + int cluster_start, + unicode_char_t base, + unicode_char_t group1, + unicode_char_t group2) +{ + /* If we are rendering with an XTIS font, we try to find a precomposed + * glyph for the cluster. + */ + if (font_info->type == THAI_FONT_XTIS) + { + PangoGlyph glyph; + int xtis_index = 0x100 * (base - 0xe00 + 0x20) + 0x30; + if (group1) + xtis_index +=8 * group1_map[group1 - 0xe30]; + if (group2) + xtis_index += group2_map[group2 - 0xe30]; + + glyph = PANGO_X_MAKE_GLYPH (font_info->subfont, xtis_index); + + if (pango_x_has_glyph (font_info->font, glyph)) + { + add_glyph (font_info, glyphs, cluster_start, glyph, FALSE); + return; + } + } + + /* If that failed, then we add compose the cluster out of three + * individual glyphs + */ + add_glyph (font_info, glyphs, cluster_start, get_glyph (font_info, base), FALSE); + if (group1) + add_glyph (font_info, glyphs, cluster_start, get_glyph (font_info, group1), TRUE); + if (group2) + add_glyph (font_info, glyphs, cluster_start, get_glyph (font_info, group2), TRUE); +} + +static void +thai_engine_shape (PangoFont *font, + const char *text, + gint length, + PangoAnalysis *analysis, + PangoGlyphString *glyphs) +{ + ThaiFontInfo *font_info; + const char *p, *next; + + unicode_char_t base = 0; + unicode_char_t group1 = 0; + unicode_char_t group2 = 0; + int cluster_start = 0; + + pango_glyph_string_set_size (glyphs, 0); + + font_info = get_font_info (font); + + p = text; + while (p < text + length) + { + int group; + unicode_char_t wc; + + next = unicode_get_utf8 (p, &wc); + + if (wc >= 0xe30 && wc < 0xe50) + group = groups[wc - 0xe30]; + else + group = 0; + + switch (group) + { + case 0: + if (base) + { + add_cluster (font_info, glyphs, cluster_start, base, group1, group2); + group1 = 0; + group2 = 0; + } + cluster_start = p - text; + base = wc; + break; + case 1: + group1 = wc; + break; + case 2: + group2 = wc; + break; + } + + p = next; + } + + if (base) + add_cluster (font_info, glyphs, cluster_start, base, group1, group2); +} + +static PangoCoverage * +thai_engine_get_coverage (PangoFont *font, + const char *lang) +{ + PangoCoverage *result = pango_coverage_new (); + + ThaiFontInfo *font_info = get_font_info (font); + + if (font_info->type != THAI_FONT_NONE) + { + unicode_char_t wc; + + for (wc = 0xe01; wc <= 0xe3a; wc++) + pango_coverage_set (result, wc, PANGO_COVERAGE_EXACT); + for (wc = 0xe3f; wc <= 0xe5b; wc++) + pango_coverage_set (result, wc, PANGO_COVERAGE_EXACT); + } + + return result; +} + +static PangoEngine * +thai_engine_x_new () +{ + PangoEngineShape *result; + + result = g_new (PangoEngineShape, 1); + + result->engine.id = "ThaiScriptEngine"; + result->engine.type = PANGO_ENGINE_TYPE_LANG; + result->engine.length = sizeof (result); + result->script_shape = thai_engine_shape; + result->get_coverage = thai_engine_get_coverage; + + return (PangoEngine *)result; +} + +/* The following three functions provide the public module API for + * Pango. If we are compiling it is a module, then we name the + * entry points script_engine_list, etc. But if we are compiling + * it for inclusion directly in Pango, then we need them to + * to have distinct names for this module, so we prepend + * _pango_thai_ + */ +#ifdef MODULE_PREFIX +#define MODULE_ENTRY(func) _pango_thai_##func +#else +#define MODULE_ENTRY(func) func +#endif + +/* List the engines contained within this module + */ +void +MODULE_ENTRY(script_engine_list) (PangoEngineInfo **engines, gint *n_engines) +{ + *engines = script_engines; + *n_engines = G_N_ELEMENTS (script_engines); +} + +/* Load a particular engine given the ID for the engine + */ +PangoEngine * +MODULE_ENTRY(script_engine_load) (const char *id) +{ + if (!strcmp (id, "ThaiScriptEngineLang")) + return thai_engine_lang_new (); + else if (!strcmp (id, "ThaiScriptEngineX")) + return thai_engine_x_new (); + else + return NULL; +} + +void +MODULE_ENTRY(script_engine_unload) (PangoEngine *engine) +{ +} + diff --git a/modules/thai/thai.c b/modules/thai/thai.c new file mode 100644 index 00000000..17d1d024 --- /dev/null +++ b/modules/thai/thai.c @@ -0,0 +1,428 @@ +/* Pango + * thai.c: + * + * Copyright (C) 1999 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include +#include "pango.h" +#include "pangox.h" +#include "utils.h" +#include +#include + +/* We handle the range U+0e01 to U+0e5b exactly + */ +static PangoEngineRange thai_ranges[] = { + { 0x0e01, 0x0e5b, "*" }, /* Thai */ +}; + +static PangoEngineInfo script_engines[] = { + { + "ThaiScriptEngineLang", + PANGO_ENGINE_TYPE_LANG, + PANGO_RENDER_TYPE_NONE, + thai_ranges, G_N_ELEMENTS(thai_ranges) + }, + { + "ThaiScriptEngineX", + PANGO_ENGINE_TYPE_SHAPE, + PANGO_RENDER_TYPE_X, + thai_ranges, G_N_ELEMENTS(thai_ranges) + } +}; + +/* + * Language script engine + */ + +static void +thai_engine_break (const char *text, + gint len, + PangoAnalysis *analysis, + PangoLogAttr *attrs) +{ +} + +static PangoEngine * +thai_engine_lang_new () +{ + PangoEngineLang *result; + + result = g_new (PangoEngineLang, 1); + + result->engine.id = "ThaiScriptEngine"; + result->engine.type = PANGO_ENGINE_TYPE_LANG; + result->engine.length = sizeof (result); + result->script_break = thai_engine_break; + + return (PangoEngine *)result; +} + +/* + * X window system script engine portion + */ + +typedef struct _ThaiFontInfo ThaiFontInfo; + +/* The type of encoding that we will use + */ +typedef enum { + THAI_FONT_NONE, + THAI_FONT_XTIS, + THAI_FONT_TIS, + THAI_FONT_ISO10646 +} ThaiFontType; + +struct _ThaiFontInfo +{ + PangoFont *font; + ThaiFontType type; + PangoXSubfont subfont; +}; + +/* All combining marks for Thai fall in the range U+0E30-U+0E50, + * so we confine our data tables to that range, and use + * default values for characters outside those ranges. + */ + +/* Map from code point to group used for rendering with XTIS fonts + * (0 == base character) + */ +static const char groups[32] = { + 0, 1, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 1, 0 +}; + +/* Map from code point to index within group 1 + * (0 == no combining mark from group 1) + */ +static const char group1_map[32] = { + 0, 1, 0, 0, 2, 3, 4, 5, + 6, 7, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Map from code point to index within group 2 + * (0 == no combining mark from group 2) + */ +static const char group2_map[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 1, 0 +}; + +/* Returns a structure with information we will use to rendering given the + * #PangoFont. This is computed once per font and cached for later retrieval. + */ +static ThaiFontInfo * +get_font_info (PangoFont *font) +{ + static const char *charsets[] = { + "xtis620.2529-1", + "xtis-0", + "tis620.2529-1", + "iso10646-1", + }; + + static const int charset_types[] = { + THAI_FONT_XTIS, + THAI_FONT_XTIS, + THAI_FONT_TIS, + THAI_FONT_ISO10646 + }; + + ThaiFontInfo *font_info; + + font_info = pango_font_get_data (font, "thai-font-info"); + if (!font_info) + { + /* No cached information not found, so we need to compute it + * from scratch + */ + PangoXSubfont *subfont_ids; + int *subfont_charsets; + int n_subfonts, i; + + font_info = g_new (ThaiFontInfo, 1); + font_info->font = font; + font_info->type = THAI_FONT_NONE; + + pango_font_set_data (font, "thai-font-info", font_info, (GDestroyNotify)g_free); + + n_subfonts = pango_x_list_subfonts (font, (char **)charsets, G_N_ELEMENTS (charsets), + &subfont_ids, &subfont_charsets); + + for (i=0; i < n_subfonts; i++) + { + ThaiFontType font_type = charset_types[subfont_charsets[i]]; + + if (font_type != THAI_FONT_ISO10646 || + pango_x_has_glyph (font, PANGO_X_MAKE_GLYPH (subfont_ids[i], 0xe01))) + { + font_info->type = font_type; + font_info->subfont = subfont_ids[i]; + + break; + } + } + + g_free (subfont_ids); + g_free (subfont_charsets); + } + + return font_info; +} + +static void +add_glyph (ThaiFontInfo *font_info, + PangoGlyphString *glyphs, + int cluster_start, + PangoGlyph glyph, + gboolean combining) +{ + PangoRectangle ink_rect, logical_rect; + int index = glyphs->num_glyphs; + + pango_glyph_string_set_size (glyphs, index + 1); + + glyphs->glyphs[index].glyph = glyph; + glyphs->glyphs[index].attr.is_cluster_start = combining ? 0 : 1; + + glyphs->log_clusters[index] = cluster_start; + + pango_font_get_glyph_extents (font_info->font, + glyphs->glyphs[index].glyph, &ink_rect, &logical_rect); + + if (combining) + { + glyphs->glyphs[index].geometry.width = + MAX (logical_rect.width, glyphs->glyphs[index - 1].geometry.width); + glyphs->glyphs[index - 1].geometry.width = 0; + glyphs->glyphs[index].geometry.x_offset = 0; + } + else + { + glyphs->glyphs[index].geometry.x_offset = 0; + glyphs->glyphs[index].geometry.width = logical_rect.width; + } + + glyphs->glyphs[index].geometry.y_offset = 0; +} + +/* Return the glyph code within the font for the given Unicode Thai + * code pointer + */ +static int +get_glyph (ThaiFontInfo *font_info, unicode_char_t wc) +{ + switch (font_info->type) + { + case THAI_FONT_NONE: + return pango_x_get_unknown_glyph (font_info->font); + case THAI_FONT_XTIS: + return PANGO_X_MAKE_GLYPH (font_info->subfont, 0x100 * (wc - 0xe00 + 0x20) + 0x30); + case THAI_FONT_TIS: + return PANGO_X_MAKE_GLYPH (font_info->subfont, wc - 0xe00 + 0xA0); + case THAI_FONT_ISO10646: + return PANGO_X_MAKE_GLYPH (font_info->subfont, wc); + } + return 0; /* Quiet GCC */ +} + +static void +add_cluster (ThaiFontInfo *font_info, + PangoGlyphString *glyphs, + int cluster_start, + unicode_char_t base, + unicode_char_t group1, + unicode_char_t group2) +{ + /* If we are rendering with an XTIS font, we try to find a precomposed + * glyph for the cluster. + */ + if (font_info->type == THAI_FONT_XTIS) + { + PangoGlyph glyph; + int xtis_index = 0x100 * (base - 0xe00 + 0x20) + 0x30; + if (group1) + xtis_index +=8 * group1_map[group1 - 0xe30]; + if (group2) + xtis_index += group2_map[group2 - 0xe30]; + + glyph = PANGO_X_MAKE_GLYPH (font_info->subfont, xtis_index); + + if (pango_x_has_glyph (font_info->font, glyph)) + { + add_glyph (font_info, glyphs, cluster_start, glyph, FALSE); + return; + } + } + + /* If that failed, then we add compose the cluster out of three + * individual glyphs + */ + add_glyph (font_info, glyphs, cluster_start, get_glyph (font_info, base), FALSE); + if (group1) + add_glyph (font_info, glyphs, cluster_start, get_glyph (font_info, group1), TRUE); + if (group2) + add_glyph (font_info, glyphs, cluster_start, get_glyph (font_info, group2), TRUE); +} + +static void +thai_engine_shape (PangoFont *font, + const char *text, + gint length, + PangoAnalysis *analysis, + PangoGlyphString *glyphs) +{ + ThaiFontInfo *font_info; + const char *p, *next; + + unicode_char_t base = 0; + unicode_char_t group1 = 0; + unicode_char_t group2 = 0; + int cluster_start = 0; + + pango_glyph_string_set_size (glyphs, 0); + + font_info = get_font_info (font); + + p = text; + while (p < text + length) + { + int group; + unicode_char_t wc; + + next = unicode_get_utf8 (p, &wc); + + if (wc >= 0xe30 && wc < 0xe50) + group = groups[wc - 0xe30]; + else + group = 0; + + switch (group) + { + case 0: + if (base) + { + add_cluster (font_info, glyphs, cluster_start, base, group1, group2); + group1 = 0; + group2 = 0; + } + cluster_start = p - text; + base = wc; + break; + case 1: + group1 = wc; + break; + case 2: + group2 = wc; + break; + } + + p = next; + } + + if (base) + add_cluster (font_info, glyphs, cluster_start, base, group1, group2); +} + +static PangoCoverage * +thai_engine_get_coverage (PangoFont *font, + const char *lang) +{ + PangoCoverage *result = pango_coverage_new (); + + ThaiFontInfo *font_info = get_font_info (font); + + if (font_info->type != THAI_FONT_NONE) + { + unicode_char_t wc; + + for (wc = 0xe01; wc <= 0xe3a; wc++) + pango_coverage_set (result, wc, PANGO_COVERAGE_EXACT); + for (wc = 0xe3f; wc <= 0xe5b; wc++) + pango_coverage_set (result, wc, PANGO_COVERAGE_EXACT); + } + + return result; +} + +static PangoEngine * +thai_engine_x_new () +{ + PangoEngineShape *result; + + result = g_new (PangoEngineShape, 1); + + result->engine.id = "ThaiScriptEngine"; + result->engine.type = PANGO_ENGINE_TYPE_LANG; + result->engine.length = sizeof (result); + result->script_shape = thai_engine_shape; + result->get_coverage = thai_engine_get_coverage; + + return (PangoEngine *)result; +} + +/* The following three functions provide the public module API for + * Pango. If we are compiling it is a module, then we name the + * entry points script_engine_list, etc. But if we are compiling + * it for inclusion directly in Pango, then we need them to + * to have distinct names for this module, so we prepend + * _pango_thai_ + */ +#ifdef MODULE_PREFIX +#define MODULE_ENTRY(func) _pango_thai_##func +#else +#define MODULE_ENTRY(func) func +#endif + +/* List the engines contained within this module + */ +void +MODULE_ENTRY(script_engine_list) (PangoEngineInfo **engines, gint *n_engines) +{ + *engines = script_engines; + *n_engines = G_N_ELEMENTS (script_engines); +} + +/* Load a particular engine given the ID for the engine + */ +PangoEngine * +MODULE_ENTRY(script_engine_load) (const char *id) +{ + if (!strcmp (id, "ThaiScriptEngineLang")) + return thai_engine_lang_new (); + else if (!strcmp (id, "ThaiScriptEngineX")) + return thai_engine_x_new (); + else + return NULL; +} + +void +MODULE_ENTRY(script_engine_unload) (PangoEngine *engine) +{ +} + diff --git a/pango/pangox.h b/pango/pangox.h index abdf148f..c81eba70 100644 --- a/pango/pangox.h +++ b/pango/pangox.h @@ -69,9 +69,9 @@ void pango_x_render_layout (Display *display, */ typedef guint16 PangoXSubfont; -#define PANGO_X_MAKE_GLYPH(subfont,index) (subfont<<16 | index) -#define PANGO_X_GLYPH_SUBFONT(glyph) (glyph>>16) -#define PANGO_X_GLYPH_INDEX(glyph) (glyph & 0xffff) +#define PANGO_X_MAKE_GLYPH(subfont,index) ((subfont)<<16 | (index)) +#define PANGO_X_GLYPH_SUBFONT(glyph) ((glyph)>>16) +#define PANGO_X_GLYPH_INDEX(glyph) ((glyph) & 0xffff) int pango_x_list_subfonts (PangoFont *font, char **charsets, -- cgit v1.2.1