2 * hebrew-fc.h: Hebrew shaper for FreeType-based backends
4 * Copyright (C) 2000, 2007 Red Hat Software
6 * Owen Taylor <otaylor@redhat.com>
7 * Dov Grobgeld <dov.grobgeld@weizmann.ac.il>
8 * Behdad Esfahbod <behdad@behdad.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
29 #include <pango/pango-ot.h>
30 #include "pango-engine.h"
31 #include "pango-utils.h"
32 #include "pangofc-font.h"
33 #include "hebrew-shaper.h"
35 /* No extra fields needed */
36 typedef PangoEngineShape HebrewEngineFc;
37 typedef PangoEngineShapeClass HebrewEngineFcClass ;
39 #define MAX_CLUSTER_CHRS 20
41 static PangoEngineScriptInfo hebrew_scripts[] = {
42 { PANGO_SCRIPT_HEBREW, "*" }
45 #define SCRIPT_ENGINE_NAME "HebrewScriptEngineFc"
46 #define RENDER_TYPE PANGO_RENDER_TYPE_FC
48 static PangoEngineInfo script_engines[] = {
51 PANGO_ENGINE_TYPE_SHAPE,
53 hebrew_scripts, G_N_ELEMENTS(hebrew_scripts)
58 get_cluster_glyphs(PangoFont *font,
66 PangoRectangle ink_rects[])
69 for (i=0; i<cluster_size; i++)
71 PangoRectangle logical_rect;
72 gunichar wc = cluster[i];
76 if (pango_get_mirror_char (wc, &mirrored_ch))
79 if (pango_is_zero_width (wc))
80 glyph_num[i] = PANGO_GLYPH_EMPTY;
83 glyph_num[i] = pango_fc_font_get_glyph ((PangoFcFont *)font, wc);
86 glyph_num[i] = PANGO_GET_UNKNOWN_GLYPH ( wc);
89 glyph[i] = glyph_num[i];
91 pango_font_get_glyph_extents (font,
92 glyph[i], &ink_rects[i], &logical_rect);
94 /* Assign the base char width to the last character in the cluster */
98 widths[cluster_size-1] = logical_rect.width;
100 else if (i < cluster_size-1)
106 add_glyph (PangoGlyphString *glyphs,
109 gboolean is_combining,
115 gint index = glyphs->num_glyphs;
117 pango_glyph_string_set_size (glyphs, index + 1);
119 glyphs->glyphs[index].glyph = glyph;
120 glyphs->glyphs[index].attr.is_cluster_start = is_combining ? 0 : 1;
122 glyphs->log_clusters[index] = cluster_start;
124 glyphs->glyphs[index].geometry.x_offset = x_offset;
125 glyphs->glyphs[index].geometry.y_offset = y_offset;
126 glyphs->glyphs[index].geometry.width = width;
130 add_cluster(PangoGlyphString *glyphs,
140 for (i=0; i<cluster_size; i++)
142 add_glyph (glyphs, cluster_start, glyph[i],
143 i == 0 ? FALSE : TRUE, width[i], x_offset[i], y_offset[i]);
148 fallback_shape (PangoEngineShape *engine G_GNUC_UNUSED,
152 const PangoAnalysis *analysis,
153 PangoGlyphString *glyphs)
156 const char *log_cluster;
157 gunichar cluster[MAX_CLUSTER_CHRS];
159 gint glyph_num[MAX_CLUSTER_CHRS];
160 gint glyph_width[MAX_CLUSTER_CHRS], x_offset[MAX_CLUSTER_CHRS], y_offset[MAX_CLUSTER_CHRS];
161 PangoRectangle ink_rects[MAX_CLUSTER_CHRS];
162 PangoGlyph glyph[MAX_CLUSTER_CHRS];
164 pango_glyph_string_set_size (glyphs, 0);
167 while (p < text + length)
170 p = hebrew_shaper_get_next_cluster (p, text + length - p,
172 cluster, &cluster_size);
173 get_cluster_glyphs(font,
183 /* Kern the glyphs! */
184 hebrew_shaper_get_cluster_kerning(cluster,
186 /* Input and output */
203 if (analysis->level % 2)
204 hebrew_shaper_bidi_reorder(glyphs);
207 static const PangoOTFeatureMap gsub_features[] =
209 {"ccmp", PANGO_OT_ALL_GLYPHS},
210 {"locl", PANGO_OT_ALL_GLYPHS},
211 {"rlig", PANGO_OT_ALL_GLYPHS},
212 /* 'dlig' should be turned-on/off-able. lets turn off for now. */
213 /* {"dlig", PANGO_OT_ALL_GLYPHS}, */
216 static const PangoOTFeatureMap gpos_features[] =
218 {"kern", PANGO_OT_ALL_GLYPHS},
219 {"mark", PANGO_OT_ALL_GLYPHS},
220 {"mkmk", PANGO_OT_ALL_GLYPHS}
224 hebrew_engine_shape (PangoEngineShape *engine,
228 const PangoAnalysis *analysis,
229 PangoGlyphString *glyphs)
231 PangoFcFont *fc_font;
233 PangoOTRulesetDescription desc;
234 const PangoOTRuleset *ruleset;
235 PangoOTBuffer *buffer;
236 guint n_gpos_features = 0;
242 g_return_if_fail (font != NULL);
243 g_return_if_fail (text != NULL);
244 g_return_if_fail (length >= 0);
245 g_return_if_fail (analysis != NULL);
247 fc_font = PANGO_FC_FONT (font);
248 face = pango_fc_font_lock_face (fc_font);
252 desc.script = analysis->script;
253 desc.language = analysis->language;
255 desc.n_static_gsub_features = G_N_ELEMENTS (gsub_features);
256 desc.static_gsub_features = gsub_features;
257 desc.n_static_gpos_features = G_N_ELEMENTS (gpos_features);
258 desc.static_gpos_features = gpos_features;
260 /* TODO populate other_features from analysis->extra_attrs */
261 desc.n_other_features = 0;
262 desc.other_features = NULL;
264 ruleset = pango_ot_ruleset_get_for_description (pango_ot_info_get (face), &desc);
266 pango_ot_ruleset_get_feature_count (ruleset, NULL, &n_gpos_features);
267 if (n_gpos_features == 0)
269 fallback_shape (engine, font, text, length, analysis, glyphs);
273 buffer = pango_ot_buffer_new (fc_font);
274 pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
276 n_chars = g_utf8_strlen (text, length);
279 for (i=0; i < n_chars; i++)
284 wc = g_utf8_get_char (p);
286 if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK)
289 if (pango_is_zero_width (wc))
290 glyph = PANGO_GLYPH_EMPTY;
295 if (analysis->level % 2)
296 g_unichar_get_mirror_char (c, &c);
298 glyph = pango_fc_font_get_glyph (fc_font, c);
302 glyph = PANGO_GET_UNKNOWN_GLYPH (wc);
304 pango_ot_buffer_add_glyph (buffer, glyph, 0, cluster);
306 p = g_utf8_next_char (p);
309 pango_ot_ruleset_substitute (ruleset, buffer);
310 pango_ot_ruleset_position (ruleset, buffer);
311 pango_ot_buffer_output (buffer, glyphs);
313 pango_ot_buffer_destroy (buffer);
316 pango_fc_font_unlock_face (fc_font);
320 hebrew_engine_fc_class_init (PangoEngineShapeClass *class)
322 class->script_shape = hebrew_engine_shape;
325 PANGO_ENGINE_SHAPE_DEFINE_TYPE (HebrewEngineFc, hebrew_engine_fc,
326 hebrew_engine_fc_class_init, NULL)
329 PANGO_MODULE_ENTRY(init) (GTypeModule *module)
331 hebrew_engine_fc_register_type (module);
335 PANGO_MODULE_ENTRY(exit) (void)
340 PANGO_MODULE_ENTRY(list) (PangoEngineInfo **engines,
343 *engines = script_engines;
344 *n_engines = G_N_ELEMENTS (script_engines);
348 PANGO_MODULE_ENTRY(create) (const char *id)
350 if (!strcmp (id, SCRIPT_ENGINE_NAME))
351 return g_object_new (hebrew_engine_fc_type, NULL);