Back to index

lightning-sunbird  0.9+nobinonly
thai-x.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  * Pango
00003  * thai-x.c: 
00004  *
00005  * ***** BEGIN LICENSE BLOCK *****
00006  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00007  *
00008  * The contents of this file are subject to the Mozilla Public License Version
00009  * 1.1 (the "License"); you may not use this file except in compliance with
00010  * the License. You may obtain a copy of the License at
00011  * http://www.mozilla.org/MPL/
00012  *
00013  * Software distributed under the License is distributed on an "AS IS" basis,
00014  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00015  * for the specific language governing rights and limitations under the
00016  * License.
00017  *
00018  * The Original Code is the Pango Library (www.pango.org).
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Red Hat Software.
00022  * Portions created by the Initial Developer are Copyright (C) 1999
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *   Author: Owen Taylor <otaylor@redhat.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include <glib.h>
00043 #include <string.h>
00044 
00045 #include "pango-engine.h"
00046 #include "pango-coverage.h"
00047 
00048 #define G_N_ELEMENTS(arr)     (sizeof (arr) / sizeof ((arr)[0]))
00049 
00050 #define ucs2tis(wc)  (unsigned int)((unsigned int)(wc) - 0x0E00 + 0xA0)
00051 #define tis2uni(c)   ((gunichar2)(c) - 0xA0 + 0x0E00)
00052 
00053 #define MAX_CLUSTER_CHRS 256
00054 #define MAX_GLYPHS       256
00055 #define GLYPH_COMBINING  256
00056 
00057 /* Define TACTIS character classes */
00058 #define CTRL         0
00059 #define NON                 1
00060 #define CONS         2
00061 #define LV                  3
00062 #define FV1                 4
00063 #define FV2                 5
00064 #define FV3                 6
00065 #define BV1                 7
00066 #define BV2                 8
00067 #define BD                  9
00068 #define TONE         10
00069 #define AD1                 11
00070 #define AD2                 12
00071 #define AD3                 13
00072 #define AV1                 14
00073 #define AV2                 15
00074 #define AV3                 16
00075 
00076 #define _ND                 0
00077 #define _NC                 1
00078 #define _UC                 (1<<1)
00079 #define _BC                 (1<<2)
00080 #define _SC                 (1<<3)
00081 #define _AV                 (1<<4)
00082 #define _BV                 (1<<5)
00083 #define _TN                 (1<<6)
00084 #define _AD                 (1<<7)
00085 #define _BD                 (1<<8)
00086 #define _AM                 (1<<9)
00087 
00088 #define NoTailCons    _NC
00089 #define UpTailCons    _UC
00090 #define BotTailCons   _BC
00091 #define SpltTailCons _SC
00092 #define Cons                   (NoTailCons|UpTailCons|BotTailCons|SpltTailCons)
00093 #define AboveVowel    _AV
00094 #define BelowVowel    _BV
00095 #define Tone                   _TN
00096 #define AboveDiac       _AD
00097 #define BelowDiac       _BD
00098 #define SaraAm                 _AM
00099 
00100 #define char_class(wc)                  TAC_char_class[(unsigned int)(wc)]
00101 #define is_char_type(wc, mask) (char_type_table[ucs2tis((wc))] & (mask))
00102 
00103 #define SCRIPT_ENGINE_NAME "ThaiScriptEngineX"
00104 #define PANGO_RENDER_TYPE_X "PangoliteRenderX"
00105 
00106 typedef guint16 PangoliteXSubfont;
00107 #define PANGO_MOZ_MAKE_GLYPH(index) ((guint32)0 | (index))
00108 
00109 /* We handle the range U+0e01 to U+0e5b exactly
00110  */
00111 static PangoliteEngineRange thai_ranges[] = {
00112   { 0x0e01, 0x0e5b, "*" },  /* Thai */
00113 };
00114 
00115 static PangoliteEngineInfo script_engines[] = {
00116   {
00117     SCRIPT_ENGINE_NAME,
00118     PANGO_ENGINE_TYPE_SHAPE,
00119     PANGO_RENDER_TYPE_X,
00120     thai_ranges, 
00121     G_N_ELEMENTS(thai_ranges)
00122   }
00123 };
00124 
00125 /*
00126  * X window system script engine portion
00127  */
00128 
00129 typedef struct _ThaiFontInfo ThaiFontInfo;
00130 
00131 /* The type of encoding that we will use
00132  */
00133 typedef enum {
00134   THAI_FONT_NONE,
00135   THAI_FONT_XTIS,
00136   THAI_FONT_TIS,
00137   THAI_FONT_TIS_MAC,
00138   THAI_FONT_TIS_WIN,
00139   THAI_FONT_ISO10646
00140 } ThaiFontType;
00141 
00142 struct _ThaiFontInfo
00143 {
00144   ThaiFontType  type;
00145   PangoliteXSubfont subfont;
00146 };
00147 
00148 /* All combining marks for Thai fall in the range U+0E30-U+0E50,
00149  * so we confine our data tables to that range, and use
00150  * default values for characters outside those ranges.
00151  */
00152 
00153 /* Map from code point to group used for rendering with XTIS fonts
00154  * (0 == base character)
00155  */
00156 static const char groups[32] = {
00157   0, 1, 0, 0, 1, 1, 1, 1,
00158   1, 1, 1, 0, 0, 0, 0, 0,
00159   0, 0, 0, 0, 0, 0, 0, 2,
00160   2, 2, 2, 2, 2, 2, 1, 0
00161 };
00162 
00163 /* Map from code point to index within group 1
00164  * (0 == no combining mark from group 1)
00165  */   
00166 static const char group1_map[32] = {
00167   0, 1, 0, 0, 2, 3, 4, 5,
00168   6, 7, 8, 0, 0, 0, 0, 0,
00169   0, 0, 0, 0, 0, 0, 0, 0,
00170   0, 0, 0, 0, 0, 0, 0, 0
00171 };
00172 
00173 /* Map from code point to index within group 2
00174  * (0 == no combining mark from group 2)
00175  */   
00176 static const char group2_map[32] = {
00177   0, 0, 0, 0, 0, 0, 0, 0,
00178   0, 0, 0, 0, 0, 0, 0, 0,
00179   0, 0, 0, 0, 0, 0, 0, 1,
00180   2, 3, 4, 5, 6, 7, 1, 0
00181 };
00182 
00183 static const gint char_type_table[256] = {
00184   /*       0,   1,   2,   3,   4,   5,   6,   7,
00185            8,   9,   A,   B,   C,   D,   E,   F  */
00186 
00187   /*00*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00188          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00189   /*10*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00190          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00191   /*20*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00192          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00193   /*30*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00194          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00195   /*40*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00196          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00197   /*50*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00198          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00199   /*60*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00200          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00201   /*70*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00202          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00203   /*80*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00204          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00205   /*90*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00206          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00207               
00208   /*A0*/ _ND, _NC, _NC, _NC, _NC, _NC, _NC, _NC,
00209          _NC, _NC, _NC, _NC, _NC, _SC, _BC, _BC,
00210   /*B0*/ _SC, _NC, _NC, _NC, _NC, _NC, _NC, _NC,
00211          _NC, _NC, _NC, _UC, _NC, _UC, _NC, _UC,
00212   /*C0*/ _NC, _NC, _NC, _NC, _ND, _NC, _ND, _NC,
00213          _NC, _NC, _NC, _NC, _UC, _NC, _NC, _ND,
00214   /*D0*/ _ND, _AV, _ND, _AM, _AV, _AV, _AV, _AV,
00215          _BV, _BV, _BD, _ND, _ND, _ND, _ND, _ND,
00216   /*E0*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _AD,
00217          _TN, _TN, _TN, _TN, _AD, _AD, _AD, _ND,
00218   /*F0*/ _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00219          _ND, _ND, _ND, _ND, _ND, _ND, _ND, _ND,
00220 };
00221 
00222 static const gint TAC_char_class[256] = {
00223   /*      0,   1,   2,   3,   4,   5,   6,   7,
00224            8,   9,   A,   B,   C,   D,   E,   F  */
00225 
00226   /*00*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,
00227          CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,
00228   /*10*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,
00229          CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,
00230   /*20*/  NON, NON, NON, NON, NON, NON, NON, NON,
00231           NON, NON, NON, NON, NON, NON, NON, NON,
00232   /*30*/  NON, NON, NON, NON, NON, NON, NON, NON,
00233           NON, NON, NON, NON, NON, NON, NON, NON,
00234   /*40*/  NON, NON, NON, NON, NON, NON, NON, NON,
00235           NON, NON, NON, NON, NON, NON, NON, NON,
00236   /*50*/  NON, NON, NON, NON, NON, NON, NON, NON,
00237           NON, NON, NON, NON, NON, NON, NON, NON,
00238   /*60*/  NON, NON, NON, NON, NON, NON, NON, NON,
00239           NON, NON, NON, NON, NON, NON, NON, NON,
00240   /*70*/  NON, NON, NON, NON, NON, NON, NON, NON,
00241           NON, NON, NON, NON, NON, NON, NON,CTRL,
00242   /*80*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,
00243          CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,
00244   /*90*/ CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,
00245          CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,CTRL,
00246   /*A0*/  NON,CONS,CONS,CONS,CONS,CONS,CONS,CONS,
00247          CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS,
00248   /*B0*/ CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS,
00249          CONS,CONS,CONS,CONS,CONS,CONS,CONS,CONS,
00250   /*C0*/ CONS,CONS,CONS,CONS, FV3,CONS, FV3,CONS,
00251          CONS,CONS,CONS,CONS,CONS,CONS,CONS, NON,
00252   /*D0*/  FV1, AV2, FV1, FV1, AV1, AV3, AV2, AV3,
00253           BV1, BV2,  BD, NON, NON, NON, NON, NON,
00254   /*E0*/   LV,  LV,  LV,  LV,  LV, FV2, NON, AD2,
00255          TONE,TONE,TONE,TONE, AD1, AD1, AD3, NON,
00256   /*F0*/  NON, NON, NON, NON, NON, NON, NON, NON,
00257           NON, NON, NON, NON, NON, NON, NON,CTRL,
00258 };
00259 
00260 static const gchar TAC_compose_and_input_check_type_table[17][17] = {
00261   /* Cn */ /* 0,   1,   2,   3,   4,   5,   6,   7,
00262      8,   9,   A,   B,   C,   D,   E,   F       */
00263   /* Cn-1 00 */      { 'X', 'A', 'A', 'A', 'A', 'A', 'A', 'R',
00264                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00265   /* 10 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00266                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00267   /* 20 */      { 'X', 'A', 'A', 'A', 'A', 'S', 'A', 'C',
00268                   'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C' },
00269   /* 30 */      {'X', 'S', 'A', 'S', 'S', 'S', 'S', 'R',
00270                  'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00271   /* 40 */      { 'X', 'S', 'A', 'A', 'S', 'S', 'A', 'R',
00272                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00273   /* 50 */      { 'X', 'A', 'A', 'A', 'A', 'S', 'A', 'R',
00274                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00275   /* 60 */      { 'X', 'A', 'A', 'A', 'S', 'A', 'S', 'R',
00276                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00277   /* 70 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00278                   'R', 'R', 'C', 'C', 'R', 'R', 'R', 'R', 'R' },
00279   /* 80 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00280                   'R', 'R', 'C', 'R', 'R', 'R', 'R', 'R', 'R' },
00281   /* 90 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00282                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00283   /* A0 */      { 'X', 'A', 'A', 'A', 'A', 'A', 'A', 'R',
00284                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00285   /* B0 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00286                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00287   /* C0 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00288                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00289   /* D0 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00290                   'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R' },
00291   /* E0 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00292                   'R', 'R', 'C', 'C', 'R', 'R', 'R', 'R', 'R' },
00293   /* F0 */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00294                   'R', 'R', 'C', 'R', 'R', 'R', 'R', 'R', 'R' },
00295   /*    */      { 'X', 'A', 'A', 'A', 'S', 'S', 'A', 'R',
00296                   'R', 'R', 'C', 'R', 'C', 'R', 'R', 'R', 'R' }
00297 };
00298 
00299 typedef struct {
00300   gint ShiftDown_TONE_AD[8];
00301   gint ShiftDownLeft_TONE_AD[8];
00302   gint ShiftLeft_TONE_AD[8];
00303   gint ShiftLeft_AV[7];
00304   gint ShiftDown_BV_BD[3];
00305   gint TailCutCons[4];
00306 } ThaiShapeTable;
00307 
00308 #define shiftdown_tone_ad(c,tbl)     ((tbl)->ShiftDown_TONE_AD[(c)-0xE7])
00309 #define shiftdownleft_tone_ad(c,tbl) ((tbl)->ShiftDownLeft_TONE_AD[(c)-0xE7])
00310 #define shiftleft_tone_ad(c,tbl)     ((tbl)->ShiftLeft_TONE_AD[(c)-0xE7])
00311 #define shiftleft_av(c,tbl)          ((tbl)->ShiftLeft_AV[(c)-0xD1])
00312 #define shiftdown_bv_bd(c,tbl)       ((tbl)->ShiftDown_BV_BD[(c)-0xD8])
00313 #define tailcutcons(c,tbl)           ((tbl)->TailCutCons[(c)-0xAD])
00314 
00315 /* Macintosh
00316  */
00317 static const ThaiShapeTable Mac_shape_table = {
00318   { 0xE7, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0xED, 0xEE },
00319   { 0xE7, 0x83, 0x84, 0x85, 0x86, 0x87, 0x8F, 0xEE },
00320   { 0x93, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x8F, 0xEE },
00321   { 0x92, 0x00, 0x00, 0x94, 0x95, 0x96, 0x97 },
00322   { 0xD8, 0xD9, 0xDA },
00323   { 0xAD, 0x00, 0x00, 0xB0 }
00324 };
00325 
00326 /* Microsoft Window
00327  */
00328 static const ThaiShapeTable Win_shape_table = {
00329     { 0xE7, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0xED, 0xEE },
00330     { 0xE7, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x99, 0xEE },
00331     { 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0x99, 0xEE },
00332     { 0x98, 0x00, 0x00, 0x81, 0x82, 0x83, 0x84 },
00333     { 0xFC, 0xFD, 0xFE },
00334     { 0x90, 0x00, 0x00, 0x80 }
00335 };
00336 
00337 /* No adjusted vowel/tonemark glyphs (tis620-0)
00338   */
00339 static const ThaiShapeTable tis620_0_shape_table = {
00340   { 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE },
00341   { 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE },
00342   { 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE },
00343   { 0xD1, 0x00, 0x00, 0xD4, 0xD5, 0xD6, 0xD7 },
00344   { 0xD8, 0xD9, 0xDA },
00345   { 0xAD, 0x00, 0x00, 0xB0 }
00346 };
00347 
00348 /* Returns a structure with information we will use to rendering given the
00349  * #PangoliteFont. This is computed once per font and cached for later retrieval.
00350  */
00351 static ThaiFontInfo *
00352 get_font_info (const char *fontCharset)
00353 {
00354   static const char *charsets[] = {
00355     "tis620-2",
00356     "tis620-1",
00357     "tis620-0",
00358     "xtis620.2529-1",
00359     "xtis-0",
00360     "tis620.2533-1",
00361     "tis620.2529-1",
00362     "iso8859-11",
00363     "iso10646-1",
00364   };
00365 
00366   static const int charset_types[] = {
00367     THAI_FONT_TIS_WIN,
00368     THAI_FONT_TIS_MAC,
00369     THAI_FONT_TIS,
00370     THAI_FONT_XTIS,
00371     THAI_FONT_XTIS,
00372     THAI_FONT_TIS,
00373     THAI_FONT_TIS,
00374     THAI_FONT_TIS,
00375     THAI_FONT_ISO10646
00376   };
00377   
00378   ThaiFontInfo *font_info = g_new(ThaiFontInfo, 1);
00379   guint        i;
00380 
00381   font_info->type = THAI_FONT_NONE;
00382   for (i = 0; i < G_N_ELEMENTS(charsets); i++) {
00383     if (strcmp(fontCharset, charsets[i]) == 0) {   
00384       font_info->type = (ThaiFontType)charset_types[i];
00385       font_info->subfont = (PangoliteXSubfont)i;
00386       break;
00387     }
00388   }
00389   return font_info;
00390 }
00391 
00392 static void
00393 add_glyph(ThaiFontInfo         *font_info,
00394           PangoliteGlyphString *glyphs,
00395           gint                 cluster_start,
00396           PangoliteGlyph       glyph,
00397           gint                 combining)
00398 {
00399   gint           index = glyphs->num_glyphs;
00400 
00401   if ((cluster_start == 0) && (index != 0))
00402      cluster_start++;
00403 
00404   pangolite_glyph_string_set_size(glyphs, index + 1);  
00405   glyphs->glyphs[index].glyph = glyph;
00406   glyphs->glyphs[index].is_cluster_start = combining;
00407   glyphs->log_clusters[index] = cluster_start;
00408 }
00409 
00410 static gint
00411 get_adjusted_glyphs_list(ThaiFontInfo *font_info,
00412                          gunichar2     *cluster,
00413                          gint         num_chrs,
00414                          PangoliteGlyph   *glyph_lists,
00415                          const ThaiShapeTable *shaping_table)
00416 {
00417   switch (num_chrs) {
00418   case 1:
00419     if (is_char_type (cluster[0], BelowVowel|BelowDiac|AboveVowel|AboveDiac|Tone)) {
00420            if (font_info->type == THAI_FONT_TIS)
00421              glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (0x20);
00422            else
00423              glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (0x7F);
00424       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00425            return 2;
00426     }
00427     else {
00428       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00429       return 1;
00430     }
00431     break;
00432     
00433   case 2:
00434     if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) &&
00435         is_char_type (cluster[1], SaraAm)) {
00436       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00437       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (0xED);
00438       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (0xD2);
00439       return 3;
00440     }
00441     else if (is_char_type (cluster[0], UpTailCons) &&
00442                is_char_type (cluster[1], SaraAm)) {
00443       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00444       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (shiftleft_tone_ad (0xED, shaping_table));
00445       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (0xD2);
00446       return 3;
00447     }
00448     else if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) &&
00449                is_char_type (cluster[1], AboveVowel)) {
00450       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00451       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00452       return 2;
00453     }
00454     else if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) &&
00455                is_char_type (cluster[1], AboveDiac|Tone)) {
00456       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00457       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (shiftdown_tone_ad (ucs2tis (cluster[1]), shaping_table));
00458       return 2;
00459     }
00460     else if (is_char_type (cluster[0], UpTailCons) &&
00461                is_char_type (cluster[1], AboveVowel)) {
00462       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00463       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (shiftleft_av (ucs2tis (cluster[1]), shaping_table));
00464       return 2;
00465     }
00466     else if (is_char_type (cluster[0], UpTailCons) &&
00467                is_char_type (cluster[1], AboveDiac|Tone)) {
00468       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00469       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (shiftdownleft_tone_ad (ucs2tis (cluster[1]), shaping_table));
00470       return 2;
00471     }
00472     else if (is_char_type (cluster[0], NoTailCons|UpTailCons) &&
00473                is_char_type (cluster[1], BelowVowel|BelowDiac)) {
00474       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00475       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00476       return 2;
00477     }
00478     else if (is_char_type (cluster[0], BotTailCons) &&
00479              is_char_type (cluster[1], BelowVowel|BelowDiac)) {
00480       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00481       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (shiftdown_bv_bd (ucs2tis (cluster[1]), shaping_table));
00482       return 2;
00483     }
00484     else if (is_char_type (cluster[0], SpltTailCons) &&
00485                is_char_type (cluster[1], BelowVowel|BelowDiac)) {
00486         glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (tailcutcons (ucs2tis (cluster[0]), shaping_table));
00487         glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00488         return 2;
00489       }
00490     else {
00491       if (font_info->type == THAI_FONT_TIS)
00492         glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (0x20);
00493       else
00494         glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (0x7F);
00495       glyph_lists[1] =
00496         PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00497       glyph_lists[2] =
00498         PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00499       return 3;
00500     }
00501     break;
00502     
00503   case 3:
00504     if (is_char_type (cluster[0], NoTailCons|BotTailCons|SpltTailCons) &&
00505         is_char_type (cluster[1], Tone) &&
00506         is_char_type (cluster[2], SaraAm)) {
00507       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00508       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (0xED);
00509       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00510       glyph_lists[3] = PANGO_MOZ_MAKE_GLYPH (0xD2);
00511       return 4;
00512     }
00513     else if (is_char_type (cluster[0], UpTailCons) &&
00514              is_char_type (cluster[1], Tone) &&
00515              is_char_type (cluster[2], SaraAm)) {
00516       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00517       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (shiftleft_tone_ad (0xED, shaping_table));
00518       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (shiftleft_tone_ad (ucs2tis (cluster[1]), shaping_table));
00519       glyph_lists[3] = PANGO_MOZ_MAKE_GLYPH (0xD2);
00520       return 4;
00521     }
00522     else if (is_char_type (cluster[0], UpTailCons) &&
00523              is_char_type (cluster[1], AboveVowel) &&
00524              is_char_type (cluster[2], AboveDiac|Tone)) {
00525       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00526       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (shiftleft_av (ucs2tis (cluster[1]), shaping_table));
00527       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (shiftleft_tone_ad (ucs2tis (cluster[2]), shaping_table));
00528       return 3;
00529     }
00530     else if (is_char_type (cluster[0], UpTailCons) &&
00531              is_char_type (cluster[1], BelowVowel) &&
00532              is_char_type (cluster[2], AboveDiac|Tone)) {
00533       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00534       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00535       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (shiftdownleft_tone_ad (ucs2tis (cluster[2]), shaping_table));
00536       return 3;
00537     }
00538     else if (is_char_type (cluster[0], NoTailCons) &&
00539              is_char_type (cluster[1], BelowVowel) &&
00540              is_char_type (cluster[2], AboveDiac|Tone)) {
00541       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00542       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00543       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table));
00544       return 3;
00545     }
00546     else if (is_char_type (cluster[0], SpltTailCons) &&
00547              is_char_type (cluster[1], BelowVowel) &&
00548              is_char_type (cluster[2], AboveDiac|Tone)) {
00549       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (tailcutcons (ucs2tis (cluster[0]), shaping_table));
00550       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00551       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table));
00552       return 3;
00553     }
00554     else if (is_char_type (cluster[0], BotTailCons) &&
00555              is_char_type (cluster[1], BelowVowel) &&
00556              is_char_type (cluster[2], AboveDiac|Tone)) {
00557       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00558       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (shiftdown_bv_bd (ucs2tis (cluster[1]), shaping_table));
00559       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (shiftdown_tone_ad (ucs2tis (cluster[2]), shaping_table));
00560       return 3;
00561     }
00562     else {
00563       glyph_lists[0] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[0]));
00564       glyph_lists[1] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[1]));
00565       glyph_lists[2] = PANGO_MOZ_MAKE_GLYPH (ucs2tis (cluster[2]));
00566       return 3;
00567     }
00568     break;
00569   }
00570   
00571   return 0;
00572 }
00573 
00574 static gint
00575 get_glyphs_list(ThaiFontInfo *font_info,
00576                 gunichar2      *cluster,
00577                 gint             num_chrs,
00578                 PangoliteGlyph      *glyph_lists)
00579 {
00580   PangoliteGlyph glyph;
00581   gint       xtis_index, i;
00582 
00583   switch (font_info->type) {
00584   case THAI_FONT_NONE:
00585     for (i = 0; i < num_chrs; i++)
00586       /* Change this to remove font dependency */
00587       glyph_lists[i] = 0; /* pangolite_x_get_unknown_glyph(font_info->font); */
00588     return num_chrs;
00589     
00590   case THAI_FONT_XTIS:
00591     /* If we are rendering with an XTIS font, we try to find a precomposed
00592      * glyph for the cluster.
00593      */
00594     xtis_index = 0x100 * (cluster[0] - 0xe00 + 0x20) + 0x30;
00595     if (cluster[1])
00596            xtis_index +=8 * group1_map[cluster[1] - 0xe30];
00597     if (cluster[2])
00598            xtis_index += group2_map[cluster[2] - 0xe30];
00599     glyph = PANGO_MOZ_MAKE_GLYPH(xtis_index);
00600     /*
00601     if (pangolite_x_has_glyph(font_info->font, glyph)) {
00602       glyph_lists[0] = glyph;
00603       return 1;
00604     }
00605     */
00606     for (i=0; i < num_chrs; i++)
00607       glyph_lists[i] = PANGO_MOZ_MAKE_GLYPH(0x100 * (cluster[i] - 0xe00 + 0x20) + 0x30);
00608     return num_chrs;
00609     
00610   case THAI_FONT_TIS:
00611     /* TIS620-0 + Wtt2.0 Extension
00612      */
00613     return get_adjusted_glyphs_list (font_info, cluster,
00614                                      num_chrs, glyph_lists, &tis620_0_shape_table);
00615     
00616   case THAI_FONT_TIS_MAC:
00617     /* MacIntosh Extension
00618      */
00619     return get_adjusted_glyphs_list(font_info, cluster,
00620                                     num_chrs, glyph_lists, &Mac_shape_table);
00621     
00622   case THAI_FONT_TIS_WIN:
00623     /* Microsoft Extension
00624      */
00625     return get_adjusted_glyphs_list(font_info, cluster,
00626                                     num_chrs, glyph_lists, &Win_shape_table);
00627     
00628   case THAI_FONT_ISO10646:
00629     for (i=0; i < num_chrs; i++)
00630       glyph_lists[i] = PANGO_MOZ_MAKE_GLYPH(cluster[i]);
00631     return num_chrs;
00632   }
00633   
00634   return 0;                 /* Quiet GCC */
00635 }
00636 
00637 static void
00638 add_cluster(ThaiFontInfo         *font_info,
00639             PangoliteGlyphString *glyphs,
00640             gint                 cluster_start,
00641             gunichar2            *cluster,
00642             gint                 num_chrs)
00643             
00644 {
00645   PangoliteGlyph glyphs_list[MAX_GLYPHS];
00646   gint           i, num_glyphs, ClusterStart=0;
00647   
00648   num_glyphs = get_glyphs_list(font_info, cluster, num_chrs, glyphs_list);
00649   for (i=0; i<num_glyphs; i++) {
00650     ClusterStart = (gint)GLYPH_COMBINING;
00651     if (i == 0)
00652       ClusterStart = num_chrs;
00653 
00654     add_glyph(font_info, glyphs, cluster_start, glyphs_list[i], ClusterStart);
00655   }
00656 }
00657 
00658 static gboolean
00659 is_wtt_composible (gunichar2 cur_wc, gunichar2 nxt_wc)
00660 {
00661   switch (TAC_compose_and_input_check_type_table[char_class(ucs2tis(cur_wc))]
00662           [char_class(ucs2tis(nxt_wc))]) {
00663   case 'A':
00664   case 'S':
00665   case 'R':
00666   case 'X':
00667     return FALSE;
00668     
00669   case 'C':
00670     return TRUE;
00671   }
00672   
00673   g_assert_not_reached();
00674   return FALSE;
00675 }
00676 
00677 static const gunichar2 *
00678 get_next_cluster(const gunichar2 *text,
00679                  gint           length,
00680                  gunichar2       *cluster,
00681                  gint           *num_chrs)
00682 {
00683   const gunichar2 *p;
00684   gint  n_chars = 0;
00685   
00686   p = text;
00687   while (p < text + length && n_chars < 3) {
00688     gunichar2 current = *p;
00689     
00690     if (n_chars == 0 ||
00691         is_wtt_composible ((gunichar2)(cluster[n_chars - 1]), current) ||
00692         (n_chars == 1 &&
00693          is_char_type (cluster[0], Cons) &&
00694          is_char_type (current, SaraAm)) ||
00695         (n_chars == 2 &&
00696          is_char_type (cluster[0], Cons) &&
00697          is_char_type (cluster[1], Tone) &&
00698          is_char_type (current, SaraAm))) {
00699       cluster[n_chars++] = current;
00700   p++;
00701     }
00702     else
00703       break;
00704   }
00705   
00706   *num_chrs = n_chars;
00707   return p;
00708 } 
00709 
00710 static void 
00711 thai_engine_shape(const char       *fontCharset,
00712                   const gunichar2   *text,
00713                   gint             length,
00714                   PangoliteAnalysis    *analysis,
00715                   PangoliteGlyphString *glyphs)
00716 {
00717   ThaiFontInfo   *font_info;
00718   const gunichar2 *p;
00719   const gunichar2 *log_cluster;
00720   gunichar2       cluster[MAX_CLUSTER_CHRS];
00721   gint           num_chrs;
00722 
00723   font_info = get_font_info(fontCharset);
00724 
00725   p = text;
00726   while (p < text + length) {
00727     log_cluster = p;
00728     p = get_next_cluster(p, text + length - p, cluster, &num_chrs);
00729     add_cluster(font_info, glyphs, log_cluster - text, cluster, num_chrs);
00730   }
00731 }
00732 
00733 static PangoliteCoverage *
00734 thai_engine_get_coverage(const char *fontCharset,
00735                          const char *lang)
00736 {
00737   PangoliteCoverage *result = pangolite_coverage_new();  
00738   ThaiFontInfo *font_info = get_font_info(fontCharset);
00739   
00740   if (font_info->type != THAI_FONT_NONE) {
00741     gunichar2 wc;
00742     
00743     for (wc = 0xe01; wc <= 0xe3a; wc++)
00744       pangolite_coverage_set(result, wc, PANGO_COVERAGE_EXACT);
00745     for (wc = 0xe3f; wc <= 0xe5b; wc++)
00746       pangolite_coverage_set(result, wc, PANGO_COVERAGE_EXACT);
00747   }
00748   
00749   return result;
00750 }
00751 
00752 static PangoliteEngine *
00753 thai_engine_x_new()
00754 {
00755   PangoliteEngineShape *result;
00756   
00757   result = g_new(PangoliteEngineShape, 1);
00758   
00759   result->engine.id = SCRIPT_ENGINE_NAME;
00760   result->engine.type = PANGO_ENGINE_TYPE_SHAPE;
00761   result->engine.length = sizeof(result);
00762   result->script_shape = thai_engine_shape;
00763   result->get_coverage = thai_engine_get_coverage;
00764 
00765   return(PangoliteEngine *)result;
00766 }
00767 
00768 /* The following three functions provide the public module API for
00769  * Pangolite. If we are compiling it is a module, then we name the
00770  * entry points script_engine_list, etc. But if we are compiling
00771  * it for inclusion directly in Pangolite, then we need them to
00772  * to have distinct names for this module, so we prepend
00773  * _pangolite_thai_x_
00774  */
00775 #ifdef X_MODULE_PREFIX
00776 #define MODULE_ENTRY(func) _pangolite_thai_x_##func
00777 #else
00778 #define MODULE_ENTRY(func) func
00779 #endif
00780 
00781 /* List the engines contained within this module
00782  */
00783 void 
00784 MODULE_ENTRY(script_engine_list)(PangoliteEngineInfo **engines, gint *n_engines)
00785 {
00786   *engines = script_engines;
00787   *n_engines = G_N_ELEMENTS(script_engines);
00788 }
00789 
00790 /* Load a particular engine given the ID for the engine
00791  */
00792 PangoliteEngine *
00793 MODULE_ENTRY(script_engine_load)(const char *id)
00794 {
00795   if (!strcmp(id, SCRIPT_ENGINE_NAME))
00796     return thai_engine_x_new();
00797   else
00798     return NULL;
00799 }
00800 
00801 void 
00802 MODULE_ENTRY(script_engine_unload)(PangoliteEngine *engine)
00803 {
00804 }