Git init
[external/pango1.0.git] / modules / thai / thai-fc.c
1 /* Pango
2  * thai-fc.c:
3  *
4  * Copyright (C) 1999, 2007 Red Hat Software
5  * Copyright (C) 2002 NECTEC
6  * Copyright (c) 1996-2000 by Sun Microsystems, Inc.
7  * Authors:
8  *   Owen Taylor <otaylor@redhat.com>
9  *   Theppitak Karoonboonyanan <thep@links.nectec.or.th>
10  *   Chookij Vanatham <Chookij.Vanatham@Eng.Sun.COM>
11  *   Behdad Esfahbod <behdad@behdad.org>
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public
24  * License along with this library; if not, write to the
25  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26  * Boston, MA 02111-1307, USA.
27  */
28
29
30 #include "config.h"
31 #include <string.h>
32
33 #include <glib.h>
34 #include "pango-ot.h"
35 #include "pango-engine.h"
36 #include "pangofc-font.h"
37
38 #include "thai-shaper.h"
39
40 /* No extra fields needed */
41 typedef PangoEngineShape      ThaiEngineFc;
42 typedef PangoEngineShapeClass ThaiEngineFcClass ;
43
44 #define SCRIPT_ENGINE_NAME "ThaiScriptEngineFc"
45 #define RENDER_TYPE PANGO_RENDER_TYPE_FC
46
47 /* We handle the range U+0e01 to U+0e5b exactly
48  */
49 static PangoEngineScriptInfo thai_scripts[] = {
50   { PANGO_SCRIPT_THAI, "*" },
51   { PANGO_SCRIPT_LAO,  "*" },
52 };
53
54 static PangoEngineInfo script_engines[] = {
55   {
56     SCRIPT_ENGINE_NAME,
57     PANGO_ENGINE_TYPE_SHAPE,
58     RENDER_TYPE,
59     thai_scripts, G_N_ELEMENTS(thai_scripts)
60   }
61 };
62
63 /* TIS-to-Unicode glyph maps for characters 0x80-0xff
64  */
65 static const int tis620_0[128] = {
66     /**/ 0,      0,      0,      0,      0,      0,      0,      0,
67     /**/ 0,      0,      0,      0,      0,      0,      0,      0,
68     /**/ 0,      0,      0,      0,      0,      0,      0,      0,
69     /**/ 0,      0,      0,      0,      0,      0,      0,      0,
70     0x0020, 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07,
71     0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f,
72     0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17,
73     0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f,
74     0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27,
75     0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f,
76     0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37,
77     0x0e38, 0x0e39, 0x0e3a,      0,      0,      0,      0, 0x0e3f,
78     0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47,
79     0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0e4e, 0x0e4f,
80     0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57,
81     0x0e58, 0x0e59, 0x0e5a, 0x0e5b,      0,      0,      0,      0
82 };
83
84 static const int tis620_1[128] = {
85     0xf89e,      0,      0, 0xf88c, 0xf88f, 0xf892, 0xf895, 0xf898,
86     0xf88b, 0xf88e, 0xf891, 0xf894, 0xf897,      0,      0, 0xf899,
87     0xf89a,      0, 0xf884, 0xf889, 0xf885, 0xf886, 0xf887, 0xf888,
88     0xf88a, 0xf88d, 0xf890, 0xf893, 0xf896,      0,      0,      0,
89     /**/ 0, 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07,
90     0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f,
91     0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17,
92     0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f,
93     0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27,
94     0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f,
95     0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37,
96     0x0e38, 0x0e39, 0x0e3a,      0,      0,      0,      0, 0x0e3f,
97     0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47,
98     0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d,      0, 0x0e4f,
99     0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57,
100     0x0e58, 0x0e59,      0,      0, 0xf89b, 0xf89c, 0xf89d,      0
101 };
102
103 static const int tis620_2[128] = {
104     0xf700, 0xf701, 0xf702, 0xf703, 0xf704, 0x2026, 0xf705, 0xf706,
105     0xf707, 0xf708, 0xf709, 0xf70a, 0xf70b, 0xf70c, 0xf70d, 0xf70e,
106     0xf70f, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
107     0xf710, 0xf711, 0xf712, 0xf713, 0xf714, 0xf715, 0xf716, 0xf717,
108     0x00a0, 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07,
109     0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f,
110     0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17,
111     0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f,
112     0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27,
113     0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f,
114     0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37,
115     0x0e38, 0x0e39, 0x0e3a,      0,      0,      0,      0, 0x0e3f,
116     0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47,
117     0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0e4e, 0x0e4f,
118     0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57,
119     0x0e58, 0x0e59, 0x0e5a, 0x0e5b, 0xf718, 0xf719, 0xf71a,      0
120 };
121
122 static const int lao_0[128] = {
123     /**/ 0,      0,      0,      0,      0,      0,      0,      0,
124     /**/ 0,      0,      0,      0,      0,      0,      0,      0,
125     /**/ 0,      0,      0,      0,      0,      0,      0,      0,
126     /**/ 0,      0,      0,      0,      0,      0,      0,      0,
127     0x0020, 0x0e81, 0x0e82,      0, 0x0e84,      0,      0, 0x0e87,
128     0x0e88,      0, 0x0e8a,      0,      0, 0x0e8d,      0,      0,
129          0,      0,      0,      0, 0x0e94, 0x0e95, 0x0e96, 0x0e97,
130     /**/ 0, 0x0e99, 0x0e9a, 0x0e9b, 0x0e9c, 0x0e9d, 0x0e9e, 0x0e9f,
131     /**/ 0, 0x0ea1, 0x0ea2, 0x0ea3,      0, 0x0ea5,      0, 0x0ea7,
132     /**/ 0,      0, 0x0eaa, 0x0eab,      0, 0x0ead, 0x0eae, 0x0eaf,
133     0x0eb0, 0x0eb1, 0x0eb2, 0x0eb3, 0x0eb4, 0x0eb5, 0x0eb6, 0x0eb7,
134     0x0eb8, 0x0eb9,      0, 0x0ebb, 0x0ebc, 0x0ebd,      0,      0,
135     0x0ec0, 0x0ec1, 0x0ec2, 0x0ec3, 0x0ec4,      0, 0x0ec6,      0,
136     0x0ec8, 0x0ec9, 0x0eca, 0x0ecb, 0x0ecc, 0x0ecd,      0,      0,
137     0x0ed0, 0x0ed1, 0x0ed2, 0x0ed3, 0x0ed4, 0x0ed5, 0x0ed6, 0x0ed7,
138     0x0ed8, 0x0ed9,      0,      0, 0x0edc, 0x0edd,      0,      0
139 };
140 static int
141 contain_glyphs(PangoFont *font, const int glyph_map[128])
142 {
143   PangoFcFont *fc_font = (PangoFcFont *)font;
144   unsigned char c;
145
146   for (c = 0; c < 0x80; c++)
147     {
148       if (glyph_map[c])
149         {
150           if (!pango_fc_font_has_char (fc_font, glyph_map[c]))
151             return 0;
152         }
153     }
154   return 1;
155 }
156
157 /* Returns a structure with information we will use to rendering given the
158  * #PangoFont. This is computed once per font and cached for later retrieval.
159  */
160 static ThaiFontInfo *
161 thai_get_font_info (PangoFont            *font,
162                     const PangoOTRuleset *ruleset)
163 {
164   ThaiFontInfo *font_info;
165   static GQuark info_id = 0;
166   
167   if (G_UNLIKELY (!info_id))
168     info_id = g_quark_from_string ("thai-font-info");
169
170   font_info = g_object_get_qdata (G_OBJECT (font), info_id);
171
172   if (G_UNLIKELY (!font_info))
173     {
174       /* No cached information not found, so we need to compute it
175        * from scratch
176        */
177       font_info = g_new (ThaiFontInfo, 1);
178       font_info->font = font;
179
180       /* detect font set by determining availibility of OT ruleset & glyphs */
181       if (pango_ot_ruleset_get_feature_count (ruleset, NULL, NULL))
182         font_info->font_set = THAI_FONT_TIS;
183       else if (contain_glyphs(font, tis620_2))
184         font_info->font_set = THAI_FONT_TIS_WIN;
185       else if (contain_glyphs(font, tis620_1))
186         font_info->font_set = THAI_FONT_TIS_MAC;
187       else
188         font_info->font_set = THAI_FONT_TIS;
189
190       g_object_set_qdata_full (G_OBJECT (font), info_id, font_info, (GDestroyNotify)g_free);
191     }
192
193   return font_info;
194 }
195
196 static gunichar
197 get_glyph_index_tis (ThaiFontInfo *font_info, guchar c)
198 {
199   if (!(c & 0x80))
200     return lao_0[c];
201
202   switch (font_info->font_set) {
203     default:
204     case THAI_FONT_NONE:    return 0;
205     case THAI_FONT_TIS:     return tis620_0[c & 0x7f];
206     case THAI_FONT_TIS_MAC: return tis620_1[c & 0x7f];
207     case THAI_FONT_TIS_WIN: return tis620_2[c & 0x7f];
208   }
209 }
210
211 PangoGlyph
212 thai_get_glyph_tis (ThaiFontInfo *font_info, guchar c)
213 {
214   return thai_get_glyph_uni (font_info, get_glyph_index_tis (font_info, c));
215 }
216
217 PangoGlyph
218 thai_make_glyph_tis (ThaiFontInfo *font_info, guchar c)
219 {
220   return thai_make_glyph_uni (font_info, get_glyph_index_tis (font_info, c));
221 }
222
223 PangoGlyph
224 thai_get_glyph_uni (ThaiFontInfo *font_info, gunichar uc)
225 {
226   return pango_fc_font_get_glyph ((PangoFcFont *)font_info->font, uc);
227 }
228
229 PangoGlyph
230 thai_make_glyph_uni (ThaiFontInfo *font_info, gunichar uc)
231 {
232   PangoGlyph result;
233   PangoFcFont *fc_font = (PangoFcFont *)font_info->font;
234
235   result = pango_fc_font_get_glyph (fc_font, uc);
236   if (result)
237     return result;
238   else
239     return PANGO_GET_UNKNOWN_GLYPH ( uc);
240 }
241
242 static const PangoOTFeatureMap gsub_features[] =
243 {
244   {"ccmp", PANGO_OT_ALL_GLYPHS},
245   {"locl", PANGO_OT_ALL_GLYPHS},
246   {"liga", PANGO_OT_ALL_GLYPHS},
247 };
248
249 static const PangoOTFeatureMap gpos_features[] =
250 {
251   {"kern", PANGO_OT_ALL_GLYPHS},
252   {"mark", PANGO_OT_ALL_GLYPHS},
253   {"mkmk", PANGO_OT_ALL_GLYPHS}
254 };
255
256 static void
257 thai_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
258                    PangoFont        *font,
259                    const char       *text,
260                    gint              length,
261                    const PangoAnalysis *analysis,
262                    PangoGlyphString *glyphs)
263 {
264   PangoFcFont *fc_font;
265   FT_Face face;
266   PangoOTRulesetDescription desc;
267   const PangoOTRuleset *ruleset;
268   PangoOTBuffer *buffer;
269   gint i;
270   ThaiFontInfo *font_info;
271
272   g_return_if_fail (font != NULL);
273   g_return_if_fail (text != NULL);
274   g_return_if_fail (length >= 0);
275   g_return_if_fail (analysis != NULL);
276
277   fc_font = PANGO_FC_FONT (font);
278   face = pango_fc_font_lock_face (fc_font);
279   if (!face)
280     return;
281
282   desc.script = analysis->script;
283   desc.language = analysis->language;
284
285   desc.n_static_gsub_features = G_N_ELEMENTS (gsub_features);
286   desc.static_gsub_features = gsub_features;
287   desc.n_static_gpos_features = G_N_ELEMENTS (gpos_features);
288   desc.static_gpos_features = gpos_features;
289
290   /* TODO populate other_features from analysis->extra_attrs */
291   desc.n_other_features = 0;
292   desc.other_features = NULL;
293
294   ruleset = pango_ot_ruleset_get_for_description (pango_ot_info_get (face), &desc);
295
296   font_info = thai_get_font_info (font, ruleset);
297
298   thai_set_glyphs (font_info, text, length, analysis->script, glyphs); 
299
300   buffer = pango_ot_buffer_new (PANGO_FC_FONT (font));
301   pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
302
303   for (i = 0; i < glyphs->num_glyphs; i++)
304     pango_ot_buffer_add_glyph (buffer,
305                                glyphs->glyphs[i].glyph,
306                                0,
307                                glyphs->log_clusters[i]);
308
309   pango_ot_ruleset_substitute (ruleset, buffer);
310   pango_ot_ruleset_position (ruleset, buffer);
311
312   pango_ot_buffer_output (buffer, glyphs);
313   pango_ot_buffer_destroy (buffer);
314 }
315
316 PangoGlyph
317 thai_make_unknown_glyph (ThaiFontInfo *font_info G_GNUC_UNUSED, gunichar uc)
318 {
319   return PANGO_GET_UNKNOWN_GLYPH (uc);
320 }
321
322 static void
323 thai_engine_fc_class_init (PangoEngineShapeClass *class)
324 {
325   class->script_shape = thai_engine_shape;
326 }
327
328 PANGO_ENGINE_SHAPE_DEFINE_TYPE (ThaiEngineFc, thai_engine_fc,
329                                 thai_engine_fc_class_init, NULL)
330
331 void
332 PANGO_MODULE_ENTRY(init) (GTypeModule *module)
333 {
334   thai_engine_fc_register_type (module);
335 }
336
337 void
338 PANGO_MODULE_ENTRY(exit) (void)
339 {
340 }
341
342 void
343 PANGO_MODULE_ENTRY(list) (PangoEngineInfo **engines,
344                           int              *n_engines)
345 {
346   *engines = script_engines;
347   *n_engines = G_N_ELEMENTS (script_engines);
348 }
349
350 PangoEngine *
351 PANGO_MODULE_ENTRY(create) (const char *id)
352 {
353   if (!strcmp (id, SCRIPT_ENGINE_NAME))
354     return g_object_new (thai_engine_fc_type, NULL);
355   else
356     return NULL;
357 }