2 * m17n-fc.c: Generic shaper using the m17n library for FreeType-based backends
4 Copyright (C) 2004, 2005
5 National Institute of Advanced Industrial Science and Technology (AIST)
6 Registration Number H15PRO112
8 This file is part of the m17n library.
10 The m17n library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public License
12 as published by the Free Software Foundation; either version 2.1 of
13 the License, or (at your option) any later version.
15 The m17n 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 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with the m17n library; if not, write to the Free
22 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30 #include <pango/pango-engine.h>
31 #include <pango/pango-utils.h>
32 #include <pango/pangofc-font.h>
35 #include <m17n-misc.h>
40 #define G_LOG_DOMAIN "M17N-Pango-FC"
42 /* Control printing of debug information. It is initialized from the
43 environment variable PANGO_M17N_FC_DEBUG. Currently, any positive
44 value turns on all debug messages. */
45 static int debug_level;
47 /* Commonly used frame on nulldevice. */
50 /* Initialize this module. The main task is to open a frame on
56 const char *envvar = g_getenv ("PANGO_M17N_FC_DEBUG");
61 debug_level = envvar ? atoi (envvar) : 0;
65 fontset = (mdatabase_find (Mfontset, msymbol ("generic"), Mnil, Mnil)
66 ? mfontset ("generic") : mfontset (NULL));
67 mface_put_prop (face, Mfontset, fontset);
68 mplist_put (param, Mface, face);
69 mplist_put (param, Mdevice, Mnil);
70 frame = mframe (param);
71 m17n_object_unref (fontset);
72 m17n_object_unref (face);
73 m17n_object_unref (param);
76 /* Finalize this module by freeing frame. */
81 m17n_object_unref (frame);
84 /* No extra fields needed for these structures. */
85 typedef PangoEngineShape M17NEngineFc;
86 typedef PangoEngineShapeClass M17NEngineFcClass;
88 #define SCRIPT_ENGINE_NAME "M17NScriptEngineFc"
89 #define RENDER_TYPE PANGO_RENDER_TYPE_FC
91 static PangoEngineScriptInfo m17n_scripts[] = {
92 { PANGO_SCRIPT_ARABIC, "*" },
93 { PANGO_SCRIPT_BENGALI, "*" },
94 { PANGO_SCRIPT_DEVANAGARI, "*" },
95 { PANGO_SCRIPT_ETHIOPIC, "*" },
96 { PANGO_SCRIPT_GEORGIAN, "*" },
97 { PANGO_SCRIPT_GUJARATI, "*" },
98 { PANGO_SCRIPT_GURMUKHI, "*" },
99 { PANGO_SCRIPT_HEBREW, "*" },
100 { PANGO_SCRIPT_KANNADA, "*" },
101 { PANGO_SCRIPT_KHMER, "*" },
102 { PANGO_SCRIPT_LAO, "*" },
103 { PANGO_SCRIPT_MALAYALAM, "*" },
104 { PANGO_SCRIPT_MYANMAR, "*" },
105 { PANGO_SCRIPT_ORIYA, "*" },
106 { PANGO_SCRIPT_SINHALA, "*" },
107 { PANGO_SCRIPT_SYRIAC, "*" },
108 { PANGO_SCRIPT_TAMIL, "*" },
109 { PANGO_SCRIPT_TELUGU, "*" },
110 { PANGO_SCRIPT_THAANA, "*" },
111 { PANGO_SCRIPT_THAI, "*" },
112 { PANGO_SCRIPT_TIBETAN, "*" },
115 static PangoEngineInfo script_engines[] = {
118 PANGO_ENGINE_TYPE_SHAPE,
120 m17n_scripts, G_N_ELEMENTS (m17n_scripts)
125 /* Convert PANGO_LANGUAGE to m17n-lib's language symbol. If m17n-lib
126 doesn't know about PANGO_LANGUAGE, return Mnil. */
129 m17n_fc_get_language (PangoLanguage *pango_language)
135 const char *lang = pango_language_to_string (pango_language);
137 language = msymbol (lang);
138 if (! msymbol_get (language, Mlanguage))
140 if (strlen (lang) <= 2)
144 /* Remove region part (e.g. "zh_CN" -> "zh"). */
147 shortlang[0] = lang[0], shortlang[1] = lang[1], shortlang[2] = 0;
148 language = msymbol (shortlang);
149 if (! msymbol_get (language, Mlanguage))
159 /* Shaper function. */
162 m17n_fc_engine_shape (PangoEngineShape *engine,
163 PangoFont *pango_font,
166 PangoAnalysis *analysis,
167 PangoGlyphString *glyphs)
169 /* Symbols for character property `category'. */
170 static MSymbol MZs, MCf;
171 static MDrawControl control;
175 MDrawGlyph *m_glyphs;
177 PangoFcFont *fc_font;
184 g_return_if_fail (pango_font != NULL);
185 g_return_if_fail (text != NULL);
186 g_return_if_fail (length >= 0);
187 g_return_if_fail (analysis != NULL);
191 char *msg = alloca (length + 1);
195 memcpy (msg, text, length);
200 g_debug ("shape \"%s\"", msg);
205 MZs = msymbol ("Zs");
206 MCf = msymbol ("Cf");
209 language = m17n_fc_get_language (analysis->language);
211 mt = mtext_from_data (text, length, MTEXT_FORMAT_UTF_8);
212 nchars = mtext_len (mt);
213 offsets = alloca (sizeof (int) * nchars);
214 g_return_if_fail (offsets != NULL);
215 for (i = 0, p = text; i < nchars; i++, p = g_utf8_next_char (p))
216 offsets[i] = p - text;
218 fc_font = PANGO_FC_FONT (pango_font);
219 fontname = (char *) FcNameUnparse (fc_font->font_pattern);
220 font = mfont_parse_name (fontname, Mfontconfig);
226 if (FcPatternGetString (fc_font->font_pattern, FC_FILE, 0, &filename)
228 mfont_put_prop (font, Mfontfile, msymbol ((char *) filename));
229 size = (int) mfont_get_prop (font, Msize);
231 mfont_put_prop (font, Msize, (void *) (size * 256));
233 g_debug (" by %s", (char *) filename);
236 mtext_put_prop (mt, 0, nchars, Mfont, font);
237 if (language != Mnil)
238 mtext_put_prop (mt, 0, nchars, Mlanguage, language);
240 control.enable_bidi = 1;
241 m_glyphs = alloca (sizeof (MDrawGlyph) * nchars * 2);
242 g_return_if_fail (m_glyphs != NULL);
243 if (mdraw_glyph_list (frame, mt, 0, nchars, &control, m_glyphs,
244 nchars * 2, &nglyphs) < 0)
246 m_glyphs = alloca (sizeof (MDrawGlyph) * nglyphs);
247 g_return_if_fail (m_glyphs != NULL);
248 mdraw_glyph_list (frame, mt, 0, nchars, &control, m_glyphs,
252 pango_glyph_string_set_size (glyphs, nglyphs);
254 for (i = 0, g = glyphs->glyphs; i < nglyphs; i++, g++)
256 if (m_glyphs[i].glyph_code >= 0)
258 g->glyph = m_glyphs[i].glyph_code;
259 g->geometry.x_offset = m_glyphs[i].x_off * PANGO_SCALE / 256;
260 g->geometry.y_offset = m_glyphs[i].y_off * PANGO_SCALE / 256;
261 g->geometry.width = m_glyphs[i].x_advance * PANGO_SCALE / 256;
265 int c = mtext_ref_char (mt, m_glyphs[i].from);
266 MSymbol category = mchar_get_prop (c, Mcategory);
267 PangoRectangle logical_rect;
272 g->geometry.width = m_glyphs[i].x_advance * PANGO_SCALE / 256;
274 else if (category == MCf)
277 g->geometry.width = 0;
281 g->glyph = pango_fc_font_get_unknown_glyph (fc_font, c);
282 pango_font_get_glyph_extents (pango_font, g->glyph, NULL,
284 g->geometry.width = logical_rect.width;
286 g->geometry.x_offset = 0;
287 g->geometry.y_offset = 0;
289 g->attr.is_cluster_start
291 || m_glyphs[i - 1].from != m_glyphs[i].from);
292 glyphs->log_clusters[i] = offsets[m_glyphs[i].from];
295 m17n_object_unref (mt);
299 /* Check if PANGO_FONT is suitable for the character WC. */
301 static PangoCoverageLevel
302 m17n_fc_engine_covers (PangoEngineShape *engine,
303 PangoFont *pango_font,
304 PangoLanguage *pango_language,
307 static gunichar last_wc = 0;
308 /* Symbols for character property `script'. */
309 static MSymbol Mlatin, Mcommon, Minherited;
310 PangoCoverage *coverage;
311 PangoCoverageLevel result;
312 PangoFcFont *fc_font;
315 MSymbol script, language;
320 Mlatin = msymbol ("latin");
321 Mcommon = msymbol ("common");
322 Minherited = msymbol ("inherited");
325 if (debug_level > 0 && wc != last_wc)
327 g_debug ("covers for U+%04X", wc);
331 coverage = pango_font_get_coverage (pango_font, pango_language);
332 result = pango_coverage_get (coverage, wc);
333 pango_coverage_unref (coverage);
335 if (result == PANGO_COVERAGE_NONE)
339 fc_font = PANGO_FC_FONT (pango_font);
340 fontname = (char *) FcNameUnparse (fc_font->font_pattern);
341 font = mfont_parse_name (fontname, Mfontconfig);
343 msymbol_name (mfont_get_prop (font, Mfamily)));
350 fc_font = PANGO_FC_FONT (pango_font);
351 fontname = (char *) FcNameUnparse (fc_font->font_pattern);
352 font = mfont_parse_name (fontname, Mfontconfig);
358 script = mchar_get_prop ((int) wc, Mscript);
359 if (script == Mcommon || script == Minherited)
360 script = mchar_get_prop ((int) wc, msymbol ("block"));
362 language = m17n_fc_get_language (pango_language);
364 check_result = mfont_check (frame, NULL, script, language, font);
367 char *result_text = (check_result == 2 ? "exact"
368 : check_result == 1 ? "approximate"
371 g_debug (" (%s,%s): %s %s",
372 (script ? msymbol_name (script) : ""),
373 (language ? msymbol_name (language) : ""),
374 msymbol_name (mfont_get_prop (font, Mfamily)),
380 return (check_result == 2 ? PANGO_COVERAGE_EXACT
381 : check_result == 1 ? PANGO_COVERAGE_APPROXIMATE
382 : PANGO_COVERAGE_FALLBACK);
386 m17n_engine_fc_class_init (PangoEngineShapeClass *class)
388 class->script_shape = m17n_fc_engine_shape;
389 class->covers = m17n_fc_engine_covers;
392 PANGO_ENGINE_SHAPE_DEFINE_TYPE (M17NEngineFc, m17n_engine_fc,
393 m17n_engine_fc_class_init, NULL)
396 PANGO_MODULE_ENTRY(init) (GTypeModule *module)
398 m17n_engine_fc_register_type (module);
405 PANGO_MODULE_ENTRY(exit) (void)
412 PANGO_MODULE_ENTRY(list) (PangoEngineInfo **engines,
415 *engines = script_engines;
416 *n_engines = G_N_ELEMENTS (script_engines);
420 PANGO_MODULE_ENTRY(create) (const char *id)
422 return (!strcmp (id, SCRIPT_ENGINE_NAME)
423 ? g_object_new (m17n_engine_fc_type, NULL)