summaryrefslogtreecommitdiff
path: root/modules/thai/thai.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/thai/thai.c')
-rw-r--r--modules/thai/thai.c428
1 files changed, 428 insertions, 0 deletions
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)
+{
+}
+