summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2000-05-08 15:50:13 +0000
committerOwen Taylor <otaylor@src.gnome.org>2000-05-08 15:50:13 +0000
commit5aea38b87e7237795178c9455d5e825e2f9507dd (patch)
tree897d7b1c9556c13eb98249b0a8e54ce9085f46bd
parent1a9eb53c12b49c53aaaf56ef40220c28bd13df84 (diff)
downloadpango-5aea38b87e7237795178c9455d5e825e2f9507dd.tar.gz
Add a simple Thai shaper. (Reasonably complete but intended mostly for an
Mon May 8 16:19:22 2000 Owen Taylor <otaylor@redhat.com> * 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.
-rw-r--r--ChangeLog12
-rw-r--r--ChangeLog.pre-1-012
-rw-r--r--ChangeLog.pre-1-1012
-rw-r--r--ChangeLog.pre-1-212
-rw-r--r--ChangeLog.pre-1-412
-rw-r--r--ChangeLog.pre-1-612
-rw-r--r--ChangeLog.pre-1-812
-rw-r--r--configure.in4
-rw-r--r--examples/viewer.c2
-rw-r--r--modules/Makefile.am3
-rw-r--r--modules/thai/.cvsignore6
-rw-r--r--modules/thai/Makefile.am20
-rw-r--r--modules/thai/thai-x.c428
-rw-r--r--modules/thai/thai.c428
-rw-r--r--pango/pangox.h6
15 files changed, 968 insertions, 13 deletions
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 <otaylor@redhat.com>
+Mon May 8 16:19:22 2000 Owen Taylor <otaylor@redhat.com>
+
+ * 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 <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
+Mon May 8 16:19:22 2000 Owen Taylor <otaylor@redhat.com>
+
+ * 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 <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
+Mon May 8 16:19:22 2000 Owen Taylor <otaylor@redhat.com>
+
+ * 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 <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
+Mon May 8 16:19:22 2000 Owen Taylor <otaylor@redhat.com>
+
+ * 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 <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
+Mon May 8 16:19:22 2000 Owen Taylor <otaylor@redhat.com>
+
+ * 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 <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
+Mon May 8 16:19:22 2000 Owen Taylor <otaylor@redhat.com>
+
+ * 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 <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
+Mon May 8 16:19:22 2000 Owen Taylor <otaylor@redhat.com>
+
+ * 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 <otaylor@redhat.com>
* 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 <iconv.h>
+
+#include <glib.h>
+#include "pango.h"
+#include "pangox.h"
+#include "utils.h"
+#include <unicode.h>
+#include <fribidi/fribidi.h>
+
+/* 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 <iconv.h>
+
+#include <glib.h>
+#include "pango.h"
+#include "pangox.h"
+#include "utils.h"
+#include <unicode.h>
+#include <fribidi/fribidi.h>
+
+/* 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,