diff options
author | Owen Taylor <otaylor@redhat.com> | 2000-05-08 15:50:13 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2000-05-08 15:50:13 +0000 |
commit | 5aea38b87e7237795178c9455d5e825e2f9507dd (patch) | |
tree | 897d7b1c9556c13eb98249b0a8e54ce9085f46bd /modules/thai/thai-x.c | |
parent | 1a9eb53c12b49c53aaaf56ef40220c28bd13df84 (diff) | |
download | pango-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.
Diffstat (limited to 'modules/thai/thai-x.c')
-rw-r--r-- | modules/thai/thai-x.c | 428 |
1 files changed, 428 insertions, 0 deletions
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) +{ +} + |