Git init
[external/pango1.0.git] / modules / indic / indic-fc.c
1 /* Pango
2  * indic-xft.c:
3  *
4  * Copyright (C) 2001, 2002 IBM Corporation
5  * Author: Eric Mader <mader@jtcsv.com>
6  * Based on arabic-xft.c by Owen Taylor <otaylor@redhat.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "config.h"
25
26 #include <string.h>
27
28 #include "indic-ot.h"
29
30 #include "pango-engine.h"
31 #include "pango-ot.h"
32 #include "pango-utils.h"
33 #include "pangofc-font.h"
34
35 typedef struct _PangoIndicInfo PangoIndicInfo;
36
37 typedef struct _IndicEngineFc IndicEngineFc;
38 typedef PangoEngineShapeClass IndicEngineFcClass ; /* No extra fields needed */
39
40 struct _IndicEngineFc
41 {
42   PangoEngineShape shapeEngine;
43   const IndicOTClassTable *classTable;
44 };
45
46 #define ENGINE_SUFFIX "ScriptEngineFc"
47 #define RENDER_TYPE PANGO_RENDER_TYPE_FC
48
49 #define INDIC_ENGINE_INFO(script) {#script ENGINE_SUFFIX, PANGO_ENGINE_TYPE_SHAPE, RENDER_TYPE, script##_scripts, G_N_ELEMENTS(script##_scripts)}
50
51 #define INDIC_OT_CLASS_TABLE(script) &script##_class_table
52
53 static PangoEngineScriptInfo deva_scripts[] = {
54   { PANGO_SCRIPT_DEVANAGARI, "*" }
55 };
56
57 static PangoEngineScriptInfo beng_scripts[] = {
58   {PANGO_SCRIPT_BENGALI, "*" }
59 };
60
61 static PangoEngineScriptInfo guru_scripts[] = {
62   { PANGO_SCRIPT_GURMUKHI, "*" }
63 };
64
65 static PangoEngineScriptInfo gujr_scripts[] = {
66   { PANGO_SCRIPT_GUJARATI, "*" }
67 };
68
69 static PangoEngineScriptInfo orya_scripts[] = {
70   { PANGO_SCRIPT_ORIYA, "*" }
71 };
72
73 static PangoEngineScriptInfo taml_scripts[] = {
74   { PANGO_SCRIPT_TAMIL, "*" }
75 };
76
77 static PangoEngineScriptInfo telu_scripts[] = {
78   { PANGO_SCRIPT_TELUGU, "*" }
79 };
80
81 static PangoEngineScriptInfo knda_scripts[] = {
82   { PANGO_SCRIPT_KANNADA, "*" }
83 };
84
85 static PangoEngineScriptInfo mlym_scripts[] = {
86   { PANGO_SCRIPT_MALAYALAM, "*" }
87 };
88
89 static PangoEngineScriptInfo sinh_scripts[] = {
90   { PANGO_SCRIPT_SINHALA, "*" }
91 };
92
93 static PangoEngineInfo script_engines[] = {
94   INDIC_ENGINE_INFO(deva), INDIC_ENGINE_INFO(beng), INDIC_ENGINE_INFO(guru),
95   INDIC_ENGINE_INFO(gujr), INDIC_ENGINE_INFO(orya), INDIC_ENGINE_INFO(taml),
96   INDIC_ENGINE_INFO(telu), INDIC_ENGINE_INFO(knda), INDIC_ENGINE_INFO(mlym),
97   INDIC_ENGINE_INFO(sinh)
98 };
99
100 /*
101  * WARNING: These entries need to be in the same order as the entries
102  * in script_engines[].
103  *
104  * FIXME: remove this requirement, either by encapsulating the order
105  * in a macro that calls a body macro that can be redefined, or by
106  * putting the pointers to the PangoEngineInfo in PangoIndicInfo...
107  */
108 static const IndicOTClassTable *indic_ot_class_tables[] = {
109   INDIC_OT_CLASS_TABLE(deva), INDIC_OT_CLASS_TABLE(beng), INDIC_OT_CLASS_TABLE(guru),
110   INDIC_OT_CLASS_TABLE(gujr), INDIC_OT_CLASS_TABLE(orya), INDIC_OT_CLASS_TABLE(taml),
111   INDIC_OT_CLASS_TABLE(telu), INDIC_OT_CLASS_TABLE(knda), INDIC_OT_CLASS_TABLE(mlym),
112   INDIC_OT_CLASS_TABLE(sinh)
113 };
114
115 static const PangoOTFeatureMap gsub_features[] =
116 {
117   {"ccmp", PANGO_OT_ALL_GLYPHS},
118   {"locl", PANGO_OT_ALL_GLYPHS},
119   {"init", init},
120   {"nukt", nukt},
121   {"akhn", akhn},
122   {"rphf", rphf},
123   {"blwf", blwf},
124   {"half", half},
125   {"pstf", pstf},
126   {"vatu", vatu},
127   {"pres", pres},
128   {"blws", blws},
129   {"abvs", abvs},
130   {"psts", psts},
131   {"haln", haln},
132   {"calt", PANGO_OT_ALL_GLYPHS}
133 };
134
135 static const PangoOTFeatureMap gpos_features[] =
136 {
137   {"blwm", blwm},
138   {"abvm", abvm},
139   {"dist", dist},
140   {"kern", PANGO_OT_ALL_GLYPHS},
141   {"mark", PANGO_OT_ALL_GLYPHS},
142   {"mkmk", PANGO_OT_ALL_GLYPHS}
143 };
144
145 static void
146 set_glyphs (PangoFont      *font,
147             const gunichar *wcs,
148             gulong         *tags,
149             glong           n_glyphs,
150             PangoOTBuffer  *buffer,
151             gboolean        process_zwj)
152 {
153   gint i;
154   PangoFcFont *fc_font;
155
156   g_assert (font);
157
158   fc_font = PANGO_FC_FONT (font);
159
160   for (i = 0; i < n_glyphs; i++)
161     {
162       guint glyph;
163
164       if (pango_is_zero_width (wcs[i]) &&
165           (!process_zwj || wcs[i] != 0x200D))
166         glyph = PANGO_GLYPH_EMPTY;
167       else
168         {
169           glyph = pango_fc_font_get_glyph (fc_font, wcs[i]);
170
171           if (!glyph)
172             glyph = PANGO_GET_UNKNOWN_GLYPH ( wcs[i]);
173         }
174       pango_ot_buffer_add_glyph (buffer, glyph, tags[i], i);
175     }
176 }
177
178 /*
179  * FIXME: should this check for null pointers, etc.?
180  */
181 static gunichar *
182 expand_text(const gchar *text, glong length, glong **offsets, glong *n_chars)
183 {
184   const gchar *p;
185   gunichar *wcs, *wco;
186   glong i, *oo;
187
188   *n_chars = g_utf8_strlen (text, length);
189   wcs      = g_new (gunichar, *n_chars);
190   *offsets = g_new (glong, *n_chars + 1);
191
192   p   = text;
193   wco = wcs;
194   oo  = *offsets;
195   for (i = 0; i < *n_chars; i++)
196     {
197       *wco++ = g_utf8_get_char (p);
198       *oo++  = p - text;
199
200       p = g_utf8_next_char (p);
201     }
202
203   *oo = p - text;
204
205   return wcs;
206 }
207
208
209 /* analysis->shape_engine has the PangoEngine... */
210 static void
211 indic_engine_shape (PangoEngineShape *engine,
212                     PangoFont        *font,
213                     const char       *text,
214                     gint              length,
215                     const PangoAnalysis *analysis,
216                     PangoGlyphString *glyphs)
217 {
218   PangoFcFont *fc_font;
219   FT_Face face;
220   PangoOTRulesetDescription desc;
221   const PangoOTRuleset *ruleset;
222   PangoOTBuffer *buffer;
223   glong i, n_chars, n_glyphs;
224   gulong *tags = NULL;
225   gunichar *wc_in = NULL, *wc_out = NULL;
226   glong *utf8_offsets = NULL;
227   glong *indices = NULL;
228   IndicEngineFc *indic_shape_engine = NULL;
229   MPreFixups *mprefixups;
230
231   g_return_if_fail (font != NULL);
232   g_return_if_fail (text != NULL);
233   g_return_if_fail (length >= 0);
234   g_return_if_fail (analysis != NULL);
235
236   fc_font = PANGO_FC_FONT (font);
237   face = pango_fc_font_lock_face (fc_font);
238   if (!face)
239     return;
240
241   indic_shape_engine = (IndicEngineFc *) engine;
242
243   wc_in    = expand_text (text, length, &utf8_offsets, &n_chars);
244
245   n_glyphs = indic_ot_reorder (wc_in, utf8_offsets, n_chars, indic_shape_engine->classTable, NULL, NULL, NULL, NULL);
246
247   wc_out  = g_new (gunichar, n_glyphs);
248   indices = g_new (glong,    n_glyphs);
249   tags    = g_new (gulong,   n_glyphs);
250
251   n_glyphs  = indic_ot_reorder (wc_in, utf8_offsets, n_chars, indic_shape_engine->classTable, wc_out, indices, tags, &mprefixups);
252
253   pango_glyph_string_set_size (glyphs, n_glyphs);
254   buffer = pango_ot_buffer_new (fc_font);
255   pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
256
257   set_glyphs(font, wc_out, tags, n_glyphs, buffer,
258              (indic_shape_engine->classTable->scriptFlags & SF_PROCESS_ZWJ) != 0);
259
260   desc.script = analysis->script;
261   desc.language = analysis->language;
262
263   desc.n_static_gsub_features = G_N_ELEMENTS (gsub_features);
264   desc.static_gsub_features = gsub_features;
265   desc.n_static_gpos_features = G_N_ELEMENTS (gpos_features);
266   desc.static_gpos_features = gpos_features;
267
268   /* TODO populate other_features from analysis->extra_attrs */
269   desc.n_other_features = 0;
270   desc.other_features = NULL;
271
272   ruleset = pango_ot_ruleset_get_for_description (pango_ot_info_get (face), &desc);
273
274   /* do gsub processing */
275   pango_ot_ruleset_substitute (ruleset, buffer);
276
277   /* Fix pre-modifiers for some scripts before base consonant */
278   if (mprefixups)
279     {
280       indic_mprefixups_apply (mprefixups, buffer);
281       indic_mprefixups_free (mprefixups);
282     }
283
284   /* do gpos processing */
285   pango_ot_ruleset_position (ruleset, buffer);
286
287   pango_ot_buffer_output (buffer, glyphs);
288
289   /* Get the right log_clusters values */
290   for (i = 0; i < glyphs->num_glyphs; i += 1)
291     glyphs->log_clusters[i] = indices[glyphs->log_clusters[i]];
292
293   pango_fc_font_unlock_face (fc_font);
294
295   pango_ot_buffer_destroy (buffer);
296   g_free (tags);
297   g_free (indices);
298   g_free (wc_out);
299   g_free (wc_in);
300   g_free (utf8_offsets);
301 }
302
303 static void
304 indic_engine_fc_class_init (PangoEngineShapeClass *class)
305 {
306   class->script_shape = indic_engine_shape;
307 }
308
309 PANGO_ENGINE_SHAPE_DEFINE_TYPE (IndicEngineFc, indic_engine_fc,
310                                 indic_engine_fc_class_init, NULL)
311
312 void
313 PANGO_MODULE_ENTRY(init) (GTypeModule *module)
314 {
315   indic_engine_fc_register_type (module);
316 }
317
318 void
319 PANGO_MODULE_ENTRY(exit) (void)
320 {
321 }
322
323 void
324 PANGO_MODULE_ENTRY(list) (PangoEngineInfo **engines,
325                           int              *n_engines)
326 {
327   *engines = script_engines;
328   *n_engines = G_N_ELEMENTS (script_engines);
329 }
330
331 PangoEngine *
332 PANGO_MODULE_ENTRY(create) (const char *id)
333 {
334   guint i;
335
336   for (i = 0; i < G_N_ELEMENTS(script_engines); i += 1)
337     {
338       if (!strcmp(id, script_engines[i].id))
339         {
340           IndicEngineFc *engine = g_object_new (indic_engine_fc_type, NULL);
341           engine->classTable = indic_ot_class_tables[i];
342
343           return (PangoEngine *)engine;
344         }
345     }
346
347   return NULL;
348 }