diff options
author | Chookij Vanatham <chookij@src.gnome.org> | 2000-11-20 22:29:02 +0000 |
---|---|---|
committer | Chookij Vanatham <chookij@src.gnome.org> | 2000-11-20 22:29:02 +0000 |
commit | 7c0ba0994df80590bb268c8449eb34350cffa6e4 (patch) | |
tree | c6e7bbbf12d7ba39125387ca69a73df672e3dd5d /modules/thai | |
parent | 4cd0ea80ed9b8d768eb4e736403ae195f18eaccd (diff) | |
download | pango-7c0ba0994df80590bb268c8449eb34350cffa6e4.tar.gz |
Added wtt clustering rule and supported Thai MS/MAC font layout.
Diffstat (limited to 'modules/thai')
-rw-r--r-- | modules/thai/thai-x.c | 692 | ||||
-rw-r--r-- | modules/thai/thai.c | 692 |
2 files changed, 1192 insertions, 192 deletions
diff --git a/modules/thai/thai-x.c b/modules/thai/thai-x.c index 6547250a..d6b2c44c 100644 --- a/modules/thai/thai-x.c +++ b/modules/thai/thai-x.c @@ -1,7 +1,14 @@ -/* Pango +/* pANGO * thai.c: * * Copyright (C) 1999 Red Hat Software + * Author: Owen Taylor <otaylor@redhat.com> + * + * Software and Language Engineering Laboratory, NECTEC + * Author: Theppitak Karoonboonyanan <thep@links.nectec.or.th> + * + * Copyright (c) 1996-2000 by Sun Microsystems, Inc. + * Author: Chookij Vanatham <Chookij.Vanatham@Eng.Sun.COM> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,10 +26,63 @@ * Boston, MA 02111-1307, USA. */ + #include <glib.h> #include "pango.h" #include "pangox.h" +#define ucs2tis(wc) (unsigned int)((unsigned int)(wc) - 0x0E00 + 0xA0) +#define tis2uni(c) ((gunichar)(c) - 0xA0 + 0x0E00) + +#define MAX_CLUSTER_CHRS 256 +#define MAX_GLYPHS 256 + +/* Define TACTIS character classes */ +#define CTRL 0 +#define NON 1 +#define CONS 2 +#define LV 3 +#define FV1 4 +#define FV2 5 +#define FV3 6 +#define BV1 7 +#define BV2 8 +#define BD 9 +#define TONE 10 +#define AD1 11 +#define AD2 12 +#define AD3 13 +#define AV1 14 +#define AV2 15 +#define AV3 16 + +#define _ND 0 +#define _NC 1 +#define _UC (1<<1) +#define _BC (1<<2) +#define _SC (1<<3) +#define _AV (1<<4) +#define _BV (1<<5) +#define _TN (1<<6) +#define _AD (1<<7) +#define _BD (1<<8) +#define _AM (1<<9) + +#define NoTailCons _NC +#define UpTailCons _UC +#define BotTailCons _BC +#define SpltTailCons _SC +#define Cons (NoTailCons|UpTailCons|BotTailCons|SpltTailCons) +#define AboveVowel _AV +#define BelowVowel _BV +#define Tone _TN +#define AboveDiac _AD +#define BelowDiac _BD +#define SaraAm _AM + +#define char_class(wc) TAC_char_class[(unsigned int)(wc)] +#define is_char_type(wc, mask) (char_type_table[ucs2tis ((wc))] & (mask)) + /* We handle the range U+0e01 to U+0e5b exactly */ static PangoEngineRange thai_ranges[] = { @@ -83,6 +143,8 @@ typedef enum { THAI_FONT_NONE, THAI_FONT_XTIS, THAI_FONT_TIS, + THAI_FONT_TIS_MAC, + THAI_FONT_TIS_WIN, THAI_FONT_ISO10646 } ThaiFontType; @@ -128,6 +190,160 @@ static const char group2_map[32] = { 2, 3, 4, 5, 6, 7, 1, 0 }; +static const gint char_type_table[256] = { + /* 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, A, B, C, D, E, F */ + + /*00*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*10*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*20*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*30*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*40*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*50*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*60*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*70*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*80*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*90*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + + /*A0*/ _ND, _NC, _NC, _NC, _NC, _NC, _NC, _NC, + _NC, _NC, _NC, _NC, _NC, _SC, _BC, _BC, + /*B0*/ _SC, _NC, _NC, _NC, _NC, _NC, _NC, _NC, + _NC, _NC, _NC, _UC, _NC, _UC, _NC, _UC, + /*C0*/ _NC, _NC, _NC, _NC, _ND, _NC, _ND, _NC, + _NC, _NC, _NC, _NC, _UC, _NC, _NC, _ND, + /*D0*/ _ND, _AV, _ND, _AM, _AV, _AV, _AV, _AV, + _BV, _BV, _BD, _ND, _ND, _ND, _ND, _ND, + /*E0*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _AD, + _TN, _TN, _TN, _TN, _AD, _AD, _AD, _ND, + /*F0*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, +}; + +static const gint TAC_char_class[256] = { + /* 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, A, B, C, D, E, F */ + + /*00*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + /*10*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + /*20*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*30*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*40*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*50*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*60*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*70*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON,CTRL, + /*80*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + /*90*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + /*A0*/ NON,CONS,CONS,CONS,CONS,CONS,CONS,CONS, + CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS, + /*B0*/ CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS, + CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS, + /*C0*/ CONS,CONS,CONS,CONS, FV3,CONS, FV3,CONS, + CONS,CONS,CONS,CONS,CONS,CONS,CONS, NON, + /*D0*/ FV1, AV2, FV1, FV1, AV1, AV3, AV2, AV3, + BV1, BV2, BD, NON, NON, NON, NON, NON, + /*E0*/ LV, LV, LV, LV, LV, FV2, NON, AD2, + TONE,TONE,TONE,TONE, AD1, AD1, AD3, NON, + /*F0*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON,CTRL, +}; + +static const gchar TAC_compose_and_input_check_type_table[17][17] = { + /* Cn */ /* 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, A, B, C, D, E, F */ + /* Cn-1 00 */ 'X', 'A', 'A', 'A', 'A', 'A', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 10 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 20 */ 'X', 'A', 'A', 'A', 'A', 'S', 'A', 'C', + 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', + /* 30 */ 'X', 'S', 'A', 'S', 'S', 'S', 'S', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 40 */ 'X', 'S', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 50 */ 'X', 'A', 'A', 'A', 'A', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 60 */ 'X', 'A', 'A', 'A', 'S', 'A', 'S', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 70 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'C', 'R', 'R', 'R', 'R', 'R', + /* 80 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'R', 'R', 'R', 'R', 'R', 'R', + /* 90 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* A0 */ 'X', 'A', 'A', 'A', 'A', 'A', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* B0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* C0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* D0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* E0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'C', 'R', 'R', 'R', 'R', 'R', + /* F0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'R', 'R', 'R', 'R', 'R', 'R', + 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'R', 'C', 'R', 'R', 'R', 'R' +}; + +typedef struct { + gint ShiftDown_TONE_AD[8]; + gint ShiftDownLeft_TONE_AD[8]; + gint ShiftLeft_TONE_AD[8]; + gint ShiftLeft_AV[7]; + gint ShiftDown_BV_BD[3]; + gint TailCutCons[4]; +} ThaiShapeTable; + +#define shiftdown_tone_ad(c,tbl) ((tbl)->ShiftDown_TONE_AD[(c)-0xE7]) +#define shiftdownleft_tone_ad(c,tbl) ((tbl)->ShiftDownLeft_TONE_AD[(c)-0xE7]) +#define shiftleft_tone_ad(c,tbl) ((tbl)->ShiftLeft_TONE_AD[(c)-0xE7]) +#define shiftleft_av(c,tbl) ((tbl)->ShiftLeft_AV[(c)-0xD1]) +#define shiftdown_bv_bd(c,tbl) ((tbl)->ShiftDown_BV_BD[(c)-0xD8]) +#define tailcutcons(c,tbl) ((tbl)->TailCutCons[(c)-0xAD]) + +/* Macintosh + */ +static const ThaiShapeTable Mac_shape_table = { + { 0xE7, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0xED, 0xEE }, + { 0xE7, 0x83, 0x84, 0x85, 0x86, 0x87, 0x8F, 0xEE }, + { 0x93, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x8F, 0xEE }, + { 0x92, 0x00, 0x00, 0x94, 0x95, 0x96, 0x97 }, + { 0xD8, 0xD9, 0xDA }, + { 0xAD, 0x00, 0x00, 0xB0 } +}; + +/* Microsoft Window + */ +static const ThaiShapeTable Win_shape_table = { + { 0xE7, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0xED, 0xEE }, + { 0xE7, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x99, 0xEE }, + { 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0x99, 0xEE }, + { 0x98, 0x00, 0x00, 0x81, 0x82, 0x83, 0x84 }, + { 0xFC, 0xFD, 0xFE }, + { 0x90, 0x00, 0x00, 0x80 } +}; + /* Returns a structure with information we will use to rendering given the * #PangoFont. This is computed once per font and cached for later retrieval. */ @@ -135,24 +351,26 @@ static ThaiFontInfo * get_font_info (PangoFont *font) { static const char *charsets[] = { + "tis620-2", + "tis620-1", + "tis620-0", "xtis620.2529-1", "xtis-0", - "tis620.2533-0", "tis620.2533-1", - "tis620.2529-0", "tis620.2529-1", "iso8859-11", "iso10646-1", }; static const int charset_types[] = { + THAI_FONT_TIS_WIN, + THAI_FONT_TIS_MAC, + THAI_FONT_TIS, THAI_FONT_XTIS, THAI_FONT_XTIS, THAI_FONT_TIS, THAI_FONT_TIS, THAI_FONT_TIS, - THAI_FONT_TIS, - THAI_FONT_TIS, THAI_FONT_ISO10646 }; @@ -160,14 +378,15 @@ get_font_info (PangoFont *font) GQuark info_id = g_quark_from_string ("thai-font-info"); font_info = g_object_get_qdata (G_OBJECT (font), info_id); + 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; + gint *subfont_charsets; + gint n_subfonts, i; font_info = g_new (ThaiFontInfo, 1); font_info->font = font; @@ -202,12 +421,12 @@ get_font_info (PangoFont *font) static void add_glyph (ThaiFontInfo *font_info, PangoGlyphString *glyphs, - int cluster_start, + gint cluster_start, PangoGlyph glyph, gboolean combining) { PangoRectangle ink_rect, logical_rect; - int index = glyphs->num_glyphs; + gint index = glyphs->num_glyphs; pango_glyph_string_set_size (glyphs, index + 1); @@ -221,10 +440,25 @@ add_glyph (ThaiFontInfo *font_info, 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; + if (font_info->type == THAI_FONT_TIS || + font_info->type == THAI_FONT_TIS_MAC || + font_info->type == THAI_FONT_TIS_WIN) + { + glyphs->glyphs[index].geometry.width = + logical_rect.width + glyphs->glyphs[index - 1].geometry.width; + if (logical_rect.width > 0) + glyphs->glyphs[index].geometry.x_offset = glyphs->glyphs[index - 1].geometry.width; + else + glyphs->glyphs[index].geometry.x_offset = glyphs->glyphs[index].geometry.width; + glyphs->glyphs[index - 1].geometry.width = 0; + } + else + { + 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 { @@ -235,63 +469,362 @@ add_glyph (ThaiFontInfo *font_info, 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, gunichar wc) +static gint +get_adjusted_glyphs_list (ThaiFontInfo *font_info, + gunichar *cluster, + gint num_chrs, + PangoGlyph **glyph_lists, + const ThaiShapeTable *shaping_table) { + switch (num_chrs) + { + case 1: + if (is_char_type (cluster[0], BelowVowel|BelowDiac|AboveVowel|AboveDiac|Tone)) + { + glyph_lists[0] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0x7F); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + return 2; + } + else + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + return 1; + } + break; + + case 2: + if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) && + is_char_type (cluster[1], SaraAm)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xED); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xD2); + return 3; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], SaraAm)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_tone_ad (0xED, shaping_table)); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xD2); + return 3; + } + else if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) && + is_char_type (cluster[1], AboveVowel)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + return 2; + } + else if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) && + is_char_type (cluster[1], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_tone_ad (ucs2tis (cluster[1]), shaping_table)); + return 2; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], AboveVowel)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_av (ucs2tis (cluster[1]), shaping_table)); + return 2; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdownleft_tone_ad (ucs2tis (cluster[1]), shaping_table)); + return 2; + } + else if (is_char_type (cluster[0], NoTailCons|UpTailCons) && + is_char_type (cluster[1], BelowVowel|BelowDiac)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + return 2; + } + else if (is_char_type (cluster[0], BotTailCons) && + is_char_type (cluster[1], BelowVowel|BelowDiac)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_bv_bd (ucs2tis (cluster[1]), shaping_table)); + return 2; + } + else if (is_char_type (cluster[0], SpltTailCons) && + is_char_type (cluster[1], BelowVowel|BelowDiac)) + { + glyph_lists[0] = PANGO_X_MAKE_GLYPH (font_info->subfont, + tailcutcons (ucs2tis (cluster[0]), shaping_table)); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + return 2; + } + else + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, 0x7F); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[2])); + return 3; + } + break; + + case 3: + if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) && + is_char_type (cluster[1], Tone) && + is_char_type (cluster[2], SaraAm)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xED); + glyph_lists[2] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[3] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xD2); + return 4; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], Tone) && + is_char_type (cluster[2], SaraAm)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_tone_ad (0xED, shaping_table)); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_tone_ad (ucs2tis (cluster[1]), shaping_table)); + glyph_lists[3] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xD2); + return 4; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], AboveVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_av (ucs2tis (cluster[1]), shaping_table)); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], BelowVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdownleft_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else if (is_char_type (cluster[0], NoTailCons) && + is_char_type (cluster[1], BelowVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = + PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else if (is_char_type (cluster[0], SpltTailCons) && + is_char_type (cluster[1], BelowVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = PANGO_X_MAKE_GLYPH (font_info->subfont, + tailcutcons (ucs2tis (cluster[0]), shaping_table)); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else if (is_char_type (cluster[0], BotTailCons) && + is_char_type (cluster[1], BelowVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_bv_bd (ucs2tis (cluster[1]), shaping_table)); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[2])); + return 3; + } + break; + } + + return 0; +} + +static gint +get_glyphs_list (ThaiFontInfo *font_info, + gunichar *cluster, + gint num_chrs, + PangoGlyph **glyph_lists) +{ + PangoGlyph glyph; + gint xtis_index; + gint i; + 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); + case THAI_FONT_NONE: + for (i=0; i < num_chrs; i++) + glyph_lists[i] = pango_x_get_unknown_glyph (font_info->font); + return num_chrs; + + case THAI_FONT_XTIS: + /* If we are rendering with an XTIS font, we try to find a precomposed + * glyph for the cluster. + */ + xtis_index = 0x100 * (cluster[0] - 0xe00 + 0x20) + 0x30; + if (cluster[1]) + xtis_index +=8 * group1_map[cluster[1] - 0xe30]; + if (cluster[2]) + xtis_index += group2_map[cluster[2] - 0xe30]; + glyph = PANGO_X_MAKE_GLYPH (font_info->subfont, xtis_index); + if (pango_x_has_glyph (font_info->font, glyph)) { + glyph_lists[0] = glyph; + return 1; + } + for (i=0; i < num_chrs; i++) + glyph_lists[i] = + PANGO_X_MAKE_GLYPH (font_info->subfont, + 0x100 * (cluster[i] - 0xe00 + 0x20) + 0x30); + return num_chrs; + + case THAI_FONT_TIS: + for (i=0; i < num_chrs; i++) + glyph_lists[i] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[i])); + return num_chrs; + + case THAI_FONT_TIS_MAC: + /* MacIntosh Extension + */ + return get_adjusted_glyphs_list (font_info, cluster, + num_chrs, glyph_lists, &Mac_shape_table); + + case THAI_FONT_TIS_WIN: + /* Microsoft Extension + */ + return get_adjusted_glyphs_list (font_info, cluster, + num_chrs, glyph_lists, &Win_shape_table); + + case THAI_FONT_ISO10646: + for (i=0; i < num_chrs; i++) + glyph_lists[i] = PANGO_X_MAKE_GLYPH (font_info->subfont, cluster[i]); + return num_chrs; } + return 0; /* Quiet GCC */ } static void -add_cluster (ThaiFontInfo *font_info, - PangoGlyphString *glyphs, - int cluster_start, - gunichar base, - gunichar group1, - gunichar group2) +add_cluster (ThaiFontInfo *font_info, + PangoGlyphString *glyphs, + gint cluster_start, + gunichar *cluster, + gint num_chrs) + +{ + PangoGlyph glyphs_list[MAX_GLYPHS]; + gint num_glyphs; + gint i; + + num_glyphs = get_glyphs_list(font_info, cluster, num_chrs, &glyphs_list); + for (i=0; i<num_glyphs; i++) + add_glyph (font_info, glyphs, cluster_start, glyphs_list[i], + i == 0 ? FALSE : TRUE); +} + +static gboolean +is_wtt_composible (gunichar cur_wc, gunichar nxt_wc) { - /* 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) + switch (TAC_compose_and_input_check_type_table[char_class (ucs2tis (cur_wc))] + [char_class (ucs2tis (nxt_wc))]) { - 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); + case 'A': + case 'S': + case 'R': + case 'X': + return FALSE; + + case 'C': + return TRUE; + } +} - if (pango_x_has_glyph (font_info->font, glyph)) +static const char * +get_next_cluster(const char *text, + gint length, + gunichar **cluster, + gint *num_chrs) +{ + const char *p; + gint n_chars = 0; + + p = text; + while (p < text + length && n_chars < 3) + { + gunichar current = g_utf8_get_char (p); + + if (n_chars == 0 || + is_wtt_composible ((gunichar)(cluster[n_chars - 1]), current) || + (n_chars == 1 && + is_char_type (cluster[0], Cons) && + is_char_type (current, SaraAm)) || + (n_chars == 2 && + is_char_type (cluster[0], Cons) && + is_char_type (cluster[1], Tone) && + is_char_type (current, SaraAm))) { - add_glyph (font_info, glyphs, cluster_start, glyph, FALSE); - return; + cluster[n_chars++] = current; + p = g_utf8_next_char (p); } + else + break; } - /* 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); + *num_chrs = n_chars; + return p; } static void @@ -303,54 +836,21 @@ thai_engine_shape (PangoFont *font, { ThaiFontInfo *font_info; const char *p; - - gunichar base = 0; - gunichar group1 = 0; - gunichar group2 = 0; - int cluster_start = 0; + const char *log_cluster; + gunichar cluster[MAX_CLUSTER_CHRS]; + gint num_chrs; pango_glyph_string_set_size (glyphs, 0); font_info = get_font_info (font); - + p = text; while (p < text + length) { - int group; - gunichar wc; - - wc = g_utf8_get_char (p); - - 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 = g_utf8_next_char (p); + log_cluster = p; + p = get_next_cluster (p, text + length - p, &cluster, &num_chrs); + add_cluster (font_info, glyphs, log_cluster - text, cluster, num_chrs); } - - if (base) - add_cluster (font_info, glyphs, cluster_start, base, group1, group2); } static PangoCoverage * @@ -382,7 +882,7 @@ thai_engine_x_new () result = g_new (PangoEngineShape, 1); result->engine.id = "ThaiScriptEngine"; - result->engine.type = PANGO_ENGINE_TYPE_LANG; + result->engine.type = PANGO_ENGINE_TYPE_SHAPE; result->engine.length = sizeof (result); result->script_shape = thai_engine_shape; result->get_coverage = thai_engine_get_coverage; diff --git a/modules/thai/thai.c b/modules/thai/thai.c index 6547250a..d6b2c44c 100644 --- a/modules/thai/thai.c +++ b/modules/thai/thai.c @@ -1,7 +1,14 @@ -/* Pango +/* pANGO * thai.c: * * Copyright (C) 1999 Red Hat Software + * Author: Owen Taylor <otaylor@redhat.com> + * + * Software and Language Engineering Laboratory, NECTEC + * Author: Theppitak Karoonboonyanan <thep@links.nectec.or.th> + * + * Copyright (c) 1996-2000 by Sun Microsystems, Inc. + * Author: Chookij Vanatham <Chookij.Vanatham@Eng.Sun.COM> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,10 +26,63 @@ * Boston, MA 02111-1307, USA. */ + #include <glib.h> #include "pango.h" #include "pangox.h" +#define ucs2tis(wc) (unsigned int)((unsigned int)(wc) - 0x0E00 + 0xA0) +#define tis2uni(c) ((gunichar)(c) - 0xA0 + 0x0E00) + +#define MAX_CLUSTER_CHRS 256 +#define MAX_GLYPHS 256 + +/* Define TACTIS character classes */ +#define CTRL 0 +#define NON 1 +#define CONS 2 +#define LV 3 +#define FV1 4 +#define FV2 5 +#define FV3 6 +#define BV1 7 +#define BV2 8 +#define BD 9 +#define TONE 10 +#define AD1 11 +#define AD2 12 +#define AD3 13 +#define AV1 14 +#define AV2 15 +#define AV3 16 + +#define _ND 0 +#define _NC 1 +#define _UC (1<<1) +#define _BC (1<<2) +#define _SC (1<<3) +#define _AV (1<<4) +#define _BV (1<<5) +#define _TN (1<<6) +#define _AD (1<<7) +#define _BD (1<<8) +#define _AM (1<<9) + +#define NoTailCons _NC +#define UpTailCons _UC +#define BotTailCons _BC +#define SpltTailCons _SC +#define Cons (NoTailCons|UpTailCons|BotTailCons|SpltTailCons) +#define AboveVowel _AV +#define BelowVowel _BV +#define Tone _TN +#define AboveDiac _AD +#define BelowDiac _BD +#define SaraAm _AM + +#define char_class(wc) TAC_char_class[(unsigned int)(wc)] +#define is_char_type(wc, mask) (char_type_table[ucs2tis ((wc))] & (mask)) + /* We handle the range U+0e01 to U+0e5b exactly */ static PangoEngineRange thai_ranges[] = { @@ -83,6 +143,8 @@ typedef enum { THAI_FONT_NONE, THAI_FONT_XTIS, THAI_FONT_TIS, + THAI_FONT_TIS_MAC, + THAI_FONT_TIS_WIN, THAI_FONT_ISO10646 } ThaiFontType; @@ -128,6 +190,160 @@ static const char group2_map[32] = { 2, 3, 4, 5, 6, 7, 1, 0 }; +static const gint char_type_table[256] = { + /* 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, A, B, C, D, E, F */ + + /*00*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*10*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*20*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*30*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*40*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*50*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*60*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*70*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*80*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + /*90*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + + /*A0*/ _ND, _NC, _NC, _NC, _NC, _NC, _NC, _NC, + _NC, _NC, _NC, _NC, _NC, _SC, _BC, _BC, + /*B0*/ _SC, _NC, _NC, _NC, _NC, _NC, _NC, _NC, + _NC, _NC, _NC, _UC, _NC, _UC, _NC, _UC, + /*C0*/ _NC, _NC, _NC, _NC, _ND, _NC, _ND, _NC, + _NC, _NC, _NC, _NC, _UC, _NC, _NC, _ND, + /*D0*/ _ND, _AV, _ND, _AM, _AV, _AV, _AV, _AV, + _BV, _BV, _BD, _ND, _ND, _ND, _ND, _ND, + /*E0*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _AD, + _TN, _TN, _TN, _TN, _AD, _AD, _AD, _ND, + /*F0*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, + _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND, +}; + +static const gint TAC_char_class[256] = { + /* 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, A, B, C, D, E, F */ + + /*00*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + /*10*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + /*20*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*30*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*40*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*50*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*60*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON, NON, + /*70*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON,CTRL, + /*80*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + /*90*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL, + /*A0*/ NON,CONS,CONS,CONS,CONS,CONS,CONS,CONS, + CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS, + /*B0*/ CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS, + CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS, + /*C0*/ CONS,CONS,CONS,CONS, FV3,CONS, FV3,CONS, + CONS,CONS,CONS,CONS,CONS,CONS,CONS, NON, + /*D0*/ FV1, AV2, FV1, FV1, AV1, AV3, AV2, AV3, + BV1, BV2, BD, NON, NON, NON, NON, NON, + /*E0*/ LV, LV, LV, LV, LV, FV2, NON, AD2, + TONE,TONE,TONE,TONE, AD1, AD1, AD3, NON, + /*F0*/ NON, NON, NON, NON, NON, NON, NON, NON, + NON, NON, NON, NON, NON, NON, NON,CTRL, +}; + +static const gchar TAC_compose_and_input_check_type_table[17][17] = { + /* Cn */ /* 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, A, B, C, D, E, F */ + /* Cn-1 00 */ 'X', 'A', 'A', 'A', 'A', 'A', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 10 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 20 */ 'X', 'A', 'A', 'A', 'A', 'S', 'A', 'C', + 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', + /* 30 */ 'X', 'S', 'A', 'S', 'S', 'S', 'S', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 40 */ 'X', 'S', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 50 */ 'X', 'A', 'A', 'A', 'A', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 60 */ 'X', 'A', 'A', 'A', 'S', 'A', 'S', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* 70 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'C', 'R', 'R', 'R', 'R', 'R', + /* 80 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'R', 'R', 'R', 'R', 'R', 'R', + /* 90 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* A0 */ 'X', 'A', 'A', 'A', 'A', 'A', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* B0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* C0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* D0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', + /* E0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'C', 'R', 'R', 'R', 'R', 'R', + /* F0 */ 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'R', 'R', 'R', 'R', 'R', 'R', + 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R', + 'R', 'R', 'C', 'R', 'C', 'R', 'R', 'R', 'R' +}; + +typedef struct { + gint ShiftDown_TONE_AD[8]; + gint ShiftDownLeft_TONE_AD[8]; + gint ShiftLeft_TONE_AD[8]; + gint ShiftLeft_AV[7]; + gint ShiftDown_BV_BD[3]; + gint TailCutCons[4]; +} ThaiShapeTable; + +#define shiftdown_tone_ad(c,tbl) ((tbl)->ShiftDown_TONE_AD[(c)-0xE7]) +#define shiftdownleft_tone_ad(c,tbl) ((tbl)->ShiftDownLeft_TONE_AD[(c)-0xE7]) +#define shiftleft_tone_ad(c,tbl) ((tbl)->ShiftLeft_TONE_AD[(c)-0xE7]) +#define shiftleft_av(c,tbl) ((tbl)->ShiftLeft_AV[(c)-0xD1]) +#define shiftdown_bv_bd(c,tbl) ((tbl)->ShiftDown_BV_BD[(c)-0xD8]) +#define tailcutcons(c,tbl) ((tbl)->TailCutCons[(c)-0xAD]) + +/* Macintosh + */ +static const ThaiShapeTable Mac_shape_table = { + { 0xE7, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0xED, 0xEE }, + { 0xE7, 0x83, 0x84, 0x85, 0x86, 0x87, 0x8F, 0xEE }, + { 0x93, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x8F, 0xEE }, + { 0x92, 0x00, 0x00, 0x94, 0x95, 0x96, 0x97 }, + { 0xD8, 0xD9, 0xDA }, + { 0xAD, 0x00, 0x00, 0xB0 } +}; + +/* Microsoft Window + */ +static const ThaiShapeTable Win_shape_table = { + { 0xE7, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0xED, 0xEE }, + { 0xE7, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x99, 0xEE }, + { 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0x99, 0xEE }, + { 0x98, 0x00, 0x00, 0x81, 0x82, 0x83, 0x84 }, + { 0xFC, 0xFD, 0xFE }, + { 0x90, 0x00, 0x00, 0x80 } +}; + /* Returns a structure with information we will use to rendering given the * #PangoFont. This is computed once per font and cached for later retrieval. */ @@ -135,24 +351,26 @@ static ThaiFontInfo * get_font_info (PangoFont *font) { static const char *charsets[] = { + "tis620-2", + "tis620-1", + "tis620-0", "xtis620.2529-1", "xtis-0", - "tis620.2533-0", "tis620.2533-1", - "tis620.2529-0", "tis620.2529-1", "iso8859-11", "iso10646-1", }; static const int charset_types[] = { + THAI_FONT_TIS_WIN, + THAI_FONT_TIS_MAC, + THAI_FONT_TIS, THAI_FONT_XTIS, THAI_FONT_XTIS, THAI_FONT_TIS, THAI_FONT_TIS, THAI_FONT_TIS, - THAI_FONT_TIS, - THAI_FONT_TIS, THAI_FONT_ISO10646 }; @@ -160,14 +378,15 @@ get_font_info (PangoFont *font) GQuark info_id = g_quark_from_string ("thai-font-info"); font_info = g_object_get_qdata (G_OBJECT (font), info_id); + 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; + gint *subfont_charsets; + gint n_subfonts, i; font_info = g_new (ThaiFontInfo, 1); font_info->font = font; @@ -202,12 +421,12 @@ get_font_info (PangoFont *font) static void add_glyph (ThaiFontInfo *font_info, PangoGlyphString *glyphs, - int cluster_start, + gint cluster_start, PangoGlyph glyph, gboolean combining) { PangoRectangle ink_rect, logical_rect; - int index = glyphs->num_glyphs; + gint index = glyphs->num_glyphs; pango_glyph_string_set_size (glyphs, index + 1); @@ -221,10 +440,25 @@ add_glyph (ThaiFontInfo *font_info, 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; + if (font_info->type == THAI_FONT_TIS || + font_info->type == THAI_FONT_TIS_MAC || + font_info->type == THAI_FONT_TIS_WIN) + { + glyphs->glyphs[index].geometry.width = + logical_rect.width + glyphs->glyphs[index - 1].geometry.width; + if (logical_rect.width > 0) + glyphs->glyphs[index].geometry.x_offset = glyphs->glyphs[index - 1].geometry.width; + else + glyphs->glyphs[index].geometry.x_offset = glyphs->glyphs[index].geometry.width; + glyphs->glyphs[index - 1].geometry.width = 0; + } + else + { + 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 { @@ -235,63 +469,362 @@ add_glyph (ThaiFontInfo *font_info, 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, gunichar wc) +static gint +get_adjusted_glyphs_list (ThaiFontInfo *font_info, + gunichar *cluster, + gint num_chrs, + PangoGlyph **glyph_lists, + const ThaiShapeTable *shaping_table) { + switch (num_chrs) + { + case 1: + if (is_char_type (cluster[0], BelowVowel|BelowDiac|AboveVowel|AboveDiac|Tone)) + { + glyph_lists[0] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0x7F); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + return 2; + } + else + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + return 1; + } + break; + + case 2: + if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) && + is_char_type (cluster[1], SaraAm)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xED); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xD2); + return 3; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], SaraAm)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_tone_ad (0xED, shaping_table)); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xD2); + return 3; + } + else if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) && + is_char_type (cluster[1], AboveVowel)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + return 2; + } + else if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) && + is_char_type (cluster[1], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_tone_ad (ucs2tis (cluster[1]), shaping_table)); + return 2; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], AboveVowel)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_av (ucs2tis (cluster[1]), shaping_table)); + return 2; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdownleft_tone_ad (ucs2tis (cluster[1]), shaping_table)); + return 2; + } + else if (is_char_type (cluster[0], NoTailCons|UpTailCons) && + is_char_type (cluster[1], BelowVowel|BelowDiac)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + return 2; + } + else if (is_char_type (cluster[0], BotTailCons) && + is_char_type (cluster[1], BelowVowel|BelowDiac)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_bv_bd (ucs2tis (cluster[1]), shaping_table)); + return 2; + } + else if (is_char_type (cluster[0], SpltTailCons) && + is_char_type (cluster[1], BelowVowel|BelowDiac)) + { + glyph_lists[0] = PANGO_X_MAKE_GLYPH (font_info->subfont, + tailcutcons (ucs2tis (cluster[0]), shaping_table)); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + return 2; + } + else + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, 0x7F); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[2])); + return 3; + } + break; + + case 3: + if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) && + is_char_type (cluster[1], Tone) && + is_char_type (cluster[2], SaraAm)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xED); + glyph_lists[2] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[3] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xD2); + return 4; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], Tone) && + is_char_type (cluster[2], SaraAm)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_tone_ad (0xED, shaping_table)); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_tone_ad (ucs2tis (cluster[1]), shaping_table)); + glyph_lists[3] = PANGO_X_MAKE_GLYPH (font_info->subfont, 0xD2); + return 4; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], AboveVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_av (ucs2tis (cluster[1]), shaping_table)); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftleft_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else if (is_char_type (cluster[0], UpTailCons) && + is_char_type (cluster[1], BelowVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdownleft_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else if (is_char_type (cluster[0], NoTailCons) && + is_char_type (cluster[1], BelowVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = + PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else if (is_char_type (cluster[0], SpltTailCons) && + is_char_type (cluster[1], BelowVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = PANGO_X_MAKE_GLYPH (font_info->subfont, + tailcutcons (ucs2tis (cluster[0]), shaping_table)); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else if (is_char_type (cluster[0], BotTailCons) && + is_char_type (cluster[1], BelowVowel) && + is_char_type (cluster[2], AboveDiac|Tone)) + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_bv_bd (ucs2tis (cluster[1]), shaping_table)); + glyph_lists[2] = PANGO_X_MAKE_GLYPH (font_info->subfont, + shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table)); + return 3; + } + else + { + glyph_lists[0] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[0])); + glyph_lists[1] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[1])); + glyph_lists[2] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[2])); + return 3; + } + break; + } + + return 0; +} + +static gint +get_glyphs_list (ThaiFontInfo *font_info, + gunichar *cluster, + gint num_chrs, + PangoGlyph **glyph_lists) +{ + PangoGlyph glyph; + gint xtis_index; + gint i; + 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); + case THAI_FONT_NONE: + for (i=0; i < num_chrs; i++) + glyph_lists[i] = pango_x_get_unknown_glyph (font_info->font); + return num_chrs; + + case THAI_FONT_XTIS: + /* If we are rendering with an XTIS font, we try to find a precomposed + * glyph for the cluster. + */ + xtis_index = 0x100 * (cluster[0] - 0xe00 + 0x20) + 0x30; + if (cluster[1]) + xtis_index +=8 * group1_map[cluster[1] - 0xe30]; + if (cluster[2]) + xtis_index += group2_map[cluster[2] - 0xe30]; + glyph = PANGO_X_MAKE_GLYPH (font_info->subfont, xtis_index); + if (pango_x_has_glyph (font_info->font, glyph)) { + glyph_lists[0] = glyph; + return 1; + } + for (i=0; i < num_chrs; i++) + glyph_lists[i] = + PANGO_X_MAKE_GLYPH (font_info->subfont, + 0x100 * (cluster[i] - 0xe00 + 0x20) + 0x30); + return num_chrs; + + case THAI_FONT_TIS: + for (i=0; i < num_chrs; i++) + glyph_lists[i] = + PANGO_X_MAKE_GLYPH (font_info->subfont, ucs2tis (cluster[i])); + return num_chrs; + + case THAI_FONT_TIS_MAC: + /* MacIntosh Extension + */ + return get_adjusted_glyphs_list (font_info, cluster, + num_chrs, glyph_lists, &Mac_shape_table); + + case THAI_FONT_TIS_WIN: + /* Microsoft Extension + */ + return get_adjusted_glyphs_list (font_info, cluster, + num_chrs, glyph_lists, &Win_shape_table); + + case THAI_FONT_ISO10646: + for (i=0; i < num_chrs; i++) + glyph_lists[i] = PANGO_X_MAKE_GLYPH (font_info->subfont, cluster[i]); + return num_chrs; } + return 0; /* Quiet GCC */ } static void -add_cluster (ThaiFontInfo *font_info, - PangoGlyphString *glyphs, - int cluster_start, - gunichar base, - gunichar group1, - gunichar group2) +add_cluster (ThaiFontInfo *font_info, + PangoGlyphString *glyphs, + gint cluster_start, + gunichar *cluster, + gint num_chrs) + +{ + PangoGlyph glyphs_list[MAX_GLYPHS]; + gint num_glyphs; + gint i; + + num_glyphs = get_glyphs_list(font_info, cluster, num_chrs, &glyphs_list); + for (i=0; i<num_glyphs; i++) + add_glyph (font_info, glyphs, cluster_start, glyphs_list[i], + i == 0 ? FALSE : TRUE); +} + +static gboolean +is_wtt_composible (gunichar cur_wc, gunichar nxt_wc) { - /* 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) + switch (TAC_compose_and_input_check_type_table[char_class (ucs2tis (cur_wc))] + [char_class (ucs2tis (nxt_wc))]) { - 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); + case 'A': + case 'S': + case 'R': + case 'X': + return FALSE; + + case 'C': + return TRUE; + } +} - if (pango_x_has_glyph (font_info->font, glyph)) +static const char * +get_next_cluster(const char *text, + gint length, + gunichar **cluster, + gint *num_chrs) +{ + const char *p; + gint n_chars = 0; + + p = text; + while (p < text + length && n_chars < 3) + { + gunichar current = g_utf8_get_char (p); + + if (n_chars == 0 || + is_wtt_composible ((gunichar)(cluster[n_chars - 1]), current) || + (n_chars == 1 && + is_char_type (cluster[0], Cons) && + is_char_type (current, SaraAm)) || + (n_chars == 2 && + is_char_type (cluster[0], Cons) && + is_char_type (cluster[1], Tone) && + is_char_type (current, SaraAm))) { - add_glyph (font_info, glyphs, cluster_start, glyph, FALSE); - return; + cluster[n_chars++] = current; + p = g_utf8_next_char (p); } + else + break; } - /* 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); + *num_chrs = n_chars; + return p; } static void @@ -303,54 +836,21 @@ thai_engine_shape (PangoFont *font, { ThaiFontInfo *font_info; const char *p; - - gunichar base = 0; - gunichar group1 = 0; - gunichar group2 = 0; - int cluster_start = 0; + const char *log_cluster; + gunichar cluster[MAX_CLUSTER_CHRS]; + gint num_chrs; pango_glyph_string_set_size (glyphs, 0); font_info = get_font_info (font); - + p = text; while (p < text + length) { - int group; - gunichar wc; - - wc = g_utf8_get_char (p); - - 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 = g_utf8_next_char (p); + log_cluster = p; + p = get_next_cluster (p, text + length - p, &cluster, &num_chrs); + add_cluster (font_info, glyphs, log_cluster - text, cluster, num_chrs); } - - if (base) - add_cluster (font_info, glyphs, cluster_start, base, group1, group2); } static PangoCoverage * @@ -382,7 +882,7 @@ thai_engine_x_new () result = g_new (PangoEngineShape, 1); result->engine.id = "ThaiScriptEngine"; - result->engine.type = PANGO_ENGINE_TYPE_LANG; + result->engine.type = PANGO_ENGINE_TYPE_SHAPE; result->engine.length = sizeof (result); result->script_shape = thai_engine_shape; result->get_coverage = thai_engine_get_coverage; |