From f8f014e6b6dce2b68a208a9ba2264e7b66353790 Mon Sep 17 00:00:00 2001 From: handa Date: Tue, 15 Jan 2008 06:37:55 +0000 Subject: [PATCH] (m17n_scripts): Completely re-written for m17n-flt. --- m17n-fc.c | 771 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 438 insertions(+), 333 deletions(-) diff --git a/m17n-fc.c b/m17n-fc.c index cc2b961..8e06fc3 100644 --- a/m17n-fc.c +++ b/m17n-fc.c @@ -1,16 +1,14 @@ /* Pango * m17n-fc.c: Generic shaper using the m17n library for FreeType-based backends - Copyright (C) 2004, 2005, 2006 + Copyright (C) 2004, 2005, 2006, 2007 National Institute of Advanced Industrial Science and Technology (AIST) Registration Number H16PRO276 - This file is part of the pango-m17n library. - - The pango-m17n library is free software; you can redistribute it - and/or modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + The library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. The pango-m17n library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty @@ -22,64 +20,23 @@ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include +#include +#include #include -#include #include -#include -#include - #ifdef G_LOG_DOMAIN #undef G_LOG_DOMAIN #endif #define G_LOG_DOMAIN "Pango-M17N-FC" -/* Control printing of debug information. It is initialized from the - environment variable PANGO_M17N_FC_DEBUG. Currently, any positive - value turns on all debug messages. */ -static int debug_level; - -/* Commonly used frame on nulldevice. */ -static MFrame *frame; - -/* Commonly used "generic" fontset. */ -static MFontset *fontset; - -/* Initialize this module. The main task is to open a frame on - nulldevice. */ - -static void -init_module () -{ - const char *envvar = g_getenv ("PANGO_M17N_FC_DEBUG"); - MPlist *param; - MFace *face; - - debug_level = envvar ? atoi (envvar) : 0; - - param = mplist (); - face = mface (); - fontset = (mdatabase_find (Mfontset, msymbol ("generic"), Mnil, Mnil) - ? mfontset ("generic") : mfontset (NULL)); - mface_put_prop (face, Mfontset, fontset); - mplist_put (param, Mface, face); - mplist_put (param, Mdevice, Mnil); - frame = mframe (param); - m17n_object_unref (face); - m17n_object_unref (param); -} - -/* Finalize this module by freeing frame. */ - -static void -fini_module () -{ - m17n_object_unref (frame); - m17n_object_unref (fontset); -} +/**************************************/ +/* Standard preamble for Pango module */ +/**************************************/ /* No extra fields needed for these structures. */ typedef PangoEngineShape M17NEngineFc; @@ -128,7 +85,6 @@ static PangoEngineScriptInfo m17n_scripts[] = { { PANGO_SCRIPT_CANADIAN_ABORIGINAL, "*" }, { PANGO_SCRIPT_YI, "*" }, -#ifdef PANGO_SCRIPT_BRAILLE { PANGO_SCRIPT_BRAILLE, "*" }, { PANGO_SCRIPT_CYPRIOT, "*" }, { PANGO_SCRIPT_LIMBU, "*" }, @@ -137,9 +93,7 @@ static PangoEngineScriptInfo m17n_scripts[] = { { PANGO_SCRIPT_LINEAR_B, "*" }, { PANGO_SCRIPT_TAI_LE, "*" }, { PANGO_SCRIPT_UGARITIC, "*" }, -#endif /* PANGO_SCRIPT_BRAILLE */ -#ifdef PANGO_SCRIPT_NEW_TAI_LUE { PANGO_SCRIPT_NEW_TAI_LUE, "*" }, { PANGO_SCRIPT_BUGINESE, "*" }, { PANGO_SCRIPT_GLAGOLITIC, "*" }, @@ -147,10 +101,6 @@ static PangoEngineScriptInfo m17n_scripts[] = { { PANGO_SCRIPT_SYLOTI_NAGRI, "*" }, { PANGO_SCRIPT_OLD_PERSIAN, "*" }, { PANGO_SCRIPT_KHAROSHTHI, "*" }, -#endif /* PANGO_SCRIPT_NEW_TAI_LUE */ - - { PANGO_SCRIPT_UNKNOWN, "*" }, - { PANGO_SCRIPT_COMMON, "" } }; @@ -163,364 +113,520 @@ static PangoEngineInfo script_engines[] = { } }; -static char * -m17n_fc_get_family (PangoFont *pango_font) -{ - PangoFcFont *pango_fc_font = PANGO_FC_FONT (pango_font); - FcChar8 *family; +/***************************/ +/* Interface with m17n-flt */ +/***************************/ - if (FcPatternGetString (pango_fc_font->font_pattern, FC_FAMILY, 0, &family) - == FcResultMatch) - return (char *) family; - return ""; -} +#include +#include -/* Convert PANGO_LANGUAGE to m17n-lib's language symbol. If m17n-lib - doesn't know about PANGO_LANGUAGE, return Mnil. */ +/* Return a pointer to the IDXth glyph in GSTRING. */ +#define GREF(GSTRING, IDX) ((GSTRING)->glyphs + (IDX)) + +/* Convert Pango scale to 26.6 fractional pixel. */ +#define PANGO_SCALE_TO_26_6(N) ((N) / (PANGO_SCALE) * (1<<6)) + +/* Convert 26.6 fractional pixel to Pango scale. */ +#define PANGO_SCALE_FROM_26_6(N) ((N) * (PANGO_SCALE) / (1<<6)) + +/* Control printing of debug information. It is initialized from the + environment variable PANGO_M17N_FC_DEBUG. Currently, any positive + value turns on all debug messages. */ +static int debug_level; + + +/* Structure containing information about OT features decoded from + MFLTOtfSpec. */ + +typedef struct { + /* Rulesets for GSUB (1st element) and GPOS (2nd element). */ + PangoOTRuleset *ruleset[2]; +} FeatureInfo; + + +/* Structure containing information about a font. */ + +typedef struct { + MFLTFont font; + PangoFcFont *pango_font; + FT_Face face; + /* Cache that maps MFLTOtfSpec->sym to FeatureInfo. */ + MPlist *otf_spec_cache; +} FontInfo; -static MSymbol -m17n_fc_get_language (PangoLanguage *pango_language) -{ - static PangoLanguage *cached_pango_language; - static MSymbol cached_language; - MSymbol language; - if (cached_pango_language == pango_language) +/* Prototypes for callback functions of FontInfo.font. */ + +static int get_glyph_id (MFLTFont *, MFLTGlyphString *, int, int); +static int get_metrics (MFLTFont *, MFLTGlyphString *, int, int); +static int check_otf (MFLTFont *, MFLTOtfSpec *); +static int drive_otf (MFLTFont *, MFLTOtfSpec *, + MFLTGlyphString *, int, int, + MFLTGlyphString *, MFLTGlyphAdjustment *); + + +/* This function works in two ways. + + If INFO is NULL, it checks if the features specified in SPEC match + with the OpenType font in OT_INFO, and return 1 (match) or 0 (no + match). + + If INFO is non-NULL, it creates a PangoOTRuleset object from SPEC + and stores it in INFO. In this case, non-existing features in SPEC + are just ignored. + + Features in SPEC are stored in an array in this format: + P P ... [ 0xFFFFFFFF [ N N ... ] ] + where + Ps are positive features that should be in the font (INFO is + NULL), or should be applied in this order (INFO is non-NULL), + + 0xFFFFFFFF is a separater between Ps and Ns (INFO is NULL), or + is a wildcard meaning that all the other features (except for + Ns) must be applied (INFO is non-NULL), + + Ns are negative features that should not be in the font (INFO + is NULL), or should not be applied (INFO is non-NULL). */ + +static int +otf_check_features (PangoOTInfo *ot_info, PangoOTTableType type, + MFLTOtfSpec *spec, FeatureInfo *info) +{ + unsigned int *features; + unsigned int langsys_tag; + guint script_idx, langsys_idx; + guint index; + guint *feature_list; + int i, j; + /* Used as an index to spec->features[] and info->ruleset[]. */ + int for_gpos = type == PANGO_OT_TABLE_GPOS; + + features = spec->features[for_gpos]; + if (! features) + return 1; + if (! pango_ot_info_find_script (ot_info, type, spec->script, &script_idx)) + /* No feature for the specified script exist. If the first + feature in SPEC is a wildcard, the remaining features are all + negative, so we can return 1. */ + return (features[0] == 0xFFFFFFFF); + langsys_tag = spec->langsys; + if (! langsys_tag) + langsys_tag = PANGO_OT_DEFAULT_LANGUAGE; + pango_ot_info_find_language (ot_info, type, script_idx, + langsys_tag, &langsys_idx, &index); + + if (index != 0xFFFF) { - return cached_language; + info->ruleset[for_gpos] = pango_ot_ruleset_new (ot_info); + pango_ot_ruleset_add_feature (info->ruleset[for_gpos], type, + index, PANGO_OT_ALL_GLYPHS); } - if (pango_language) + for (i = 0; features[i] && features[i] != 0xFFFFFFFF; i++) { - const char *lang = pango_language_to_string (pango_language); - - language = msymbol (lang); - if (! msymbol_get (language, Mlanguage)) + if (pango_ot_info_find_feature (ot_info, type, features[i], + script_idx, langsys_idx, &index)) { - if (strlen (lang) <= 2) - language = Mnil; - else + if (info) { - /* Remove region part (e.g. "zh_CN" -> "zh"). */ - char shortlang[3]; - - shortlang[0] = lang[0], shortlang[1] = lang[1], shortlang[2] = 0; - language = msymbol (shortlang); - if (! msymbol_get (language, Mlanguage)) - language = Mnil; + if (! info->ruleset[for_gpos]) + info->ruleset[for_gpos] = pango_ot_ruleset_new (ot_info); + pango_ot_ruleset_add_feature (info->ruleset[for_gpos], type, + index, PANGO_OT_ALL_GLYPHS); } } + else + { + if (! info) + return 0; + } } - else - language = Mnil; - cached_pango_language = pango_language; - cached_language = language; - return language; + if (! features[i]) + /* No wildcard, no negative features. */ + return 1; + + feature_list = pango_ot_info_list_features (ot_info, type, 0, + script_idx, langsys_idx); + if (! feature_list) + /* No feature for the specified script/language exist. As the + remaining features are all negative, we can return 1. */ + return 1; + + if (! info) + { + /* Check if the remaining features don't appear in + FEATURE_LIST. */ + for (i++; features[i]; i++) + for (j = 0; feature_list[j]; j++) + if (features[i] == feature_list[j]) + return 0; + return 1; + } + + /* Add all features in FEATURE_LIST except for those appearing in + FEATURES. */ + for (i = 0; feature_list[i]; i++) + { + guint tag = feature_list[i]; + + for (j = 0; features[j] && tag != features[j]; j++); + if (! features[j]) + { + pango_ot_info_find_feature (ot_info, type, tag, + script_idx, langsys_idx, &index); + if (! info->ruleset[for_gpos]) + info->ruleset[for_gpos] = pango_ot_ruleset_new (ot_info); + pango_ot_ruleset_add_feature (info->ruleset[for_gpos], type, index, + PANGO_OT_ALL_GLYPHS); + } + } + return 1; } -/* Return a list of FONT-SPECs specified in the current fontset for - displaying SCRIPT in LANGUAGE. Callers must unref the returned - plist. */ +/* Return a FeatureInfo object (newly created if necessary) for the + font in FONT_INFO and for the OpenType feature specification in + SPEC. */ -MPlist * -m17n_fc_lookup_fontset (MSymbol script, MSymbol language) +static FeatureInfo * +get_feature_info (FontInfo *font_info, MFLTOtfSpec *spec) { - static MSymbol cached_script, cached_language; - static MPlist *cached_plist; - MPlist *plist; + FeatureInfo *feature_info; + PangoOTInfo *ot_info; - if (cached_script == script && cached_language == language) + if (! spec->features[0] && ! spec->features[1]) + return NULL; + if (font_info->otf_spec_cache) { - m17n_object_ref (cached_plist); - return cached_plist; + feature_info = mplist_get (font_info->otf_spec_cache, spec->sym); + if (feature_info) + return feature_info; } - plist = mfontset_lookup (fontset, script, language, Mnil); + else + font_info->otf_spec_cache = mplist (); + feature_info = g_new0 (FeatureInfo, 1); + mplist_push (font_info->otf_spec_cache, spec->sym, feature_info); + ot_info = pango_ot_info_get (font_info->face); + otf_check_features (ot_info, PANGO_OT_TABLE_GSUB, spec, feature_info); + otf_check_features (ot_info, PANGO_OT_TABLE_GPOS, spec, feature_info); + + return feature_info; +} + + +/* Free the object pointed by FONT_INFO. */ - if (mplist_key (plist) == Mnil) +static void +free_font_info (FontInfo *font_info) +{ + if (font_info->otf_spec_cache) { - /* List up languages that have entries for SCRIPT. */ - MPlist *ll = mfontset_lookup (fontset, script, Mt, Mnil); + MPlist *p; - if (! ll) + for (p = font_info->otf_spec_cache; mplist_key (p) != Mnil; + p = mplist_next (p)) { - /* No entry for SCRIPT. Return fallback FONT-SPECs. */ - m17n_object_unref (plist); - plist = mfontset_lookup (fontset, Mnil, Mnil, Mnil); + FeatureInfo *feature_info = mplist_value (p); + + if (feature_info->ruleset[0]) + g_object_unref (feature_info->ruleset[0]); + if (feature_info->ruleset[1]) + g_object_unref (feature_info->ruleset[1]); } - else + m17n_object_unref (font_info->otf_spec_cache); + } + pango_fc_font_unlock_face (font_info->pango_font); + g_free (font_info); +} + + +/* Return a FontInfo object corresponding to FONT. It is newly + created if necessary. */ + +static FontInfo * +get_font_info (PangoFont *font) +{ + FontInfo *font_info; + static GQuark info_id = 0; + + if (G_UNLIKELY (! info_id)) + info_id = g_quark_from_string ("FontInfo"); + font_info = g_object_get_qdata (G_OBJECT (font), info_id); + if (G_UNLIKELY (! font_info)) + { + PangoFontDescription *desc; + const char *family_name; + char *buf; + int len, i; + + font_info = g_new0 (FontInfo, 1); + font_info->pango_font = PANGO_FC_FONT (font); + font_info->face = pango_fc_font_lock_face (font_info->pango_font); + desc = pango_font_describe_with_absolute_size (font); + family_name = pango_font_description_get_family (desc); + if (family_name) { - if (mplist_length (ll) == 1) - { - /* If there's just one language, return FONT-SPECs for it. */ - m17n_object_unref (plist); - language = mplist_key (ll); - if (language == Mt) - language = Mnil; - plist = mfontset_lookup (fontset, script, mplist_key (ll), Mnil); - } - else - /* Sumup FONT-SPECs for all languages. */ - for (; mplist_key (ll) != Mnil; ll = mplist_next (ll)) - { - MPlist *pl; - - language = mplist_key (ll); - if (language == Mt) - language = Mnil; - for (pl = mfontset_lookup (fontset, script, language, Mnil); - mplist_key (pl) != Mnil; pl = mplist_next (pl)) - mplist_add (plist, mplist_key (pl), mplist_value (pl)); - } + len = strlen (family_name); + buf = g_alloca (len + 1); + for (i = 0; i < len + 1; i++) + buf[i] = tolower (family_name[i]); + font_info->font.family = msymbol (buf); } + font_info->font.x_ppem = font_info->font.y_ppem + = PANGO_SCALE_TO_26_6 (pango_font_description_get_size (desc)); + pango_font_description_free (desc); + font_info->font.check_otf = check_otf; + font_info->font.get_glyph_id = get_glyph_id; + font_info->font.get_metrics = get_metrics; + font_info->font.drive_otf = drive_otf; + g_object_set_qdata_full (G_OBJECT (font), info_id, + font_info, (GDestroyNotify) free_font_info); } - cached_language = language; - cached_script = script; - cached_plist = plist; - m17n_object_ref (plist); - return plist; + return font_info; } +/* Four callback functions for MFLTFont. */ -typedef struct +static int +get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to) { - PangoFcFont *pango_fc_font; - MFont *font; -} M17NFontInfo; + FontInfo *font_info = (FontInfo *) font; + MFLTGlyph *g = gstring->glyphs + from, *g_end = g + (to - from); + int err = 0; -static void -m17n_fc_free_font_info (gpointer data) + for (; g < g_end; g++) + { + if (! g->encoded) + { + g->code = pango_fc_font_get_glyph (font_info->pango_font, g->code); + g->encoded = 1; + err |= (! g->code); + } + } + return err; +} + +static int +get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to) { - M17NFontInfo *font_info = data; + FontInfo *font_info = (FontInfo *) font; + MFLTGlyph *g = gstring->glyphs + from, *g_end = g + (to - from); + int err = 0; - if (font_info->font) + for (; g < g_end; g++) { - mfont_close (font_info->font); - pango_fc_font_unlock_face (font_info->pango_fc_font); + if (! g->measured) + { + PangoRectangle inc, logical; + + if (! g->encoded) + g->code = pango_fc_font_get_glyph (font_info->pango_font, g->code); + pango_font_get_glyph_extents (PANGO_FONT (font_info->pango_font), + g->code, &inc, &logical); + g->lbearing = PANGO_SCALE_TO_26_6 (inc.x); + g->rbearing = PANGO_SCALE_TO_26_6 (inc.x + inc.width); + g->xadv = PANGO_SCALE_TO_26_6 (logical.width); + g->yadv = 0; + g->ascent = - PANGO_SCALE_TO_26_6 (inc.y); + g->descent = PANGO_SCALE_TO_26_6 (inc.height + inc.y); + g->measured = 1; + err |= (! g->code); + } } - g_free (data); + return err; } -static MFont * -m17n_fc_get_font (PangoFont *pango_font) +static int +check_otf (MFLTFont *font, MFLTOtfSpec *spec) { - GQuark info_id = g_quark_from_string ("m17n-font-info"); - M17NFontInfo *font_info; + FontInfo *font_info = (FontInfo *) font; + PangoOTInfo *ot_info = pango_ot_info_get (font_info->face); + + if (! ot_info) + return 0; + if (! otf_check_features (ot_info, PANGO_OT_TABLE_GSUB, spec, NULL) + || ! otf_check_features (ot_info, PANGO_OT_TABLE_GPOS, spec, NULL)) + return 0; + return 1; +} - font_info = g_object_get_qdata (G_OBJECT (pango_font), info_id); - if (! font_info) +static int +drive_otf (MFLTFont *font, MFLTOtfSpec *spec, + MFLTGlyphString *in, int from, int to, + MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment) +{ + FontInfo *font_info = (FontInfo *) font; + PangoOTBuffer *buffer; + FeatureInfo *feature_info; + PangoGlyphString *glyphs; + int i; + + buffer = pango_ot_buffer_new (font_info->pango_font); + for (i = from; i < to; i++) + pango_ot_buffer_add_glyph (buffer, in->glyphs[i].code, 0, i); + feature_info = get_feature_info (font_info, spec); + if (! feature_info) + goto simple_copy; + if (feature_info->ruleset[0]) + pango_ot_ruleset_substitute (feature_info->ruleset[0], buffer); + if (feature_info->ruleset[1]) + pango_ot_ruleset_position (feature_info->ruleset[1], buffer); + glyphs = pango_glyph_string_new (); + pango_ot_buffer_output (buffer, glyphs); + for (i = 0; i < glyphs->num_glyphs; i++) { - PangoFcFont *pango_fc_font = PANGO_FC_FONT (pango_font); - FT_Face ft_face = pango_fc_font_lock_face (pango_fc_font); - - font_info = g_new (M17NFontInfo, 1); - font_info->pango_fc_font = pango_fc_font; - font_info->font = mfont_encapsulate (frame, Mfreetype, ft_face); - g_object_set_qdata_full (G_OBJECT (pango_font), info_id, font_info, - (GDestroyNotify) m17n_fc_free_font_info); + PangoGlyphInfo *glyph_info = glyphs->glyphs + i; + MFLTGlyph *g; + + out->glyphs[out->used] = in->glyphs[glyphs->log_clusters[i]]; + g = out->glyphs + out->used++; + if (g->code != glyph_info->glyph) + { + g->c = 0; + g->code = glyph_info->glyph; + g->measured = 0; + } + g->xoff = PANGO_SCALE_TO_26_6 (glyph_info->geometry.x_offset); + g->yoff = PANGO_SCALE_TO_26_6 (glyph_info->geometry.y_offset); + g->xadv = PANGO_SCALE_TO_26_6 (glyph_info->geometry.width); + g->yadv = 0; + adjustment[i].set = 0; } - return font_info->font; + pango_ot_buffer_destroy (buffer); + pango_glyph_string_free (glyphs); + return to; + + simple_copy: + pango_ot_buffer_destroy (buffer); + for (i = from; i < to; i++) + out->glyphs[out->used++] = in->glyphs[i]; + return to; } /* Shaper function. */ +/* Shape TEXT of length GSTRING->used by a font in FONT_INFO, and + store the result in GLYPHS. GSTRING->glyphs is not yet allocated + but GSTRING->allocated tells how many glyphs to allocate. */ + +static int +shape_text (const char *text, int *offsets, MFLTGlyphString *gstring, + FontInfo *font_info, PangoGlyphString *glyphs) +{ + int i; + PangoGlyphInfo *g; + MFLTGlyph *mg; + + gstring->glyphs = g_newa (MFLTGlyph, gstring->allocated); + for (i = 0; i < gstring->used; i++) + gstring->glyphs[i].c = g_utf8_get_char (text + offsets[i]); + i = mflt_run (gstring, 0, gstring->used, (MFLTFont *) font_info, NULL); + if (i < 0) + return i; + + pango_glyph_string_set_size (glyphs, gstring->used); + + for (i = 0, g = glyphs->glyphs, mg = gstring->glyphs; i < gstring->used; + i++, g++, mg++) + { + g->glyph = mg->code; + g->geometry.x_offset = PANGO_SCALE_FROM_26_6 (mg->xoff); + g->geometry.y_offset = PANGO_SCALE_FROM_26_6 (mg->yoff); + g->geometry.width = PANGO_SCALE_FROM_26_6 (mg->xadv); + g->attr.is_cluster_start = (i == 0 || mg->from != mg[-1].from); + glyphs->log_clusters[i] + = (g->attr.is_cluster_start ? offsets[mg->from] + : glyphs->log_clusters[i - 1]); + } + return 0; +} + static void m17n_fc_engine_shape (PangoEngineShape *engine, - PangoFont *pango_font, + PangoFont *font, const char *text, int length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { - /* Symbols for character property `category'. */ - static MSymbol MZs, MCf; - static MDrawControl control; - MSymbol language; - PangoGlyphInfo *g; - MText *mt; - MDrawGlyph *m_glyphs; - int nchars, nglyphs; - MFont *font; + FontInfo *font_info; + MFLTGlyphString gstring; int i; - const char *p; + const char *p, *pend; int *offsets; - g_return_if_fail (pango_font != NULL); + g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); g_return_if_fail (length >= 0); g_return_if_fail (analysis != NULL); - if (! MZs) - { - MZs = msymbol ("Zs"); - MCf = msymbol ("Cf"); - memset (&control, 0, sizeof control); - } + font_info = get_font_info (font); - language = m17n_fc_get_language (analysis->language); + gstring.glyph_size = sizeof (MFLTGlyph); + gstring.used = 0; + gstring.r2l = analysis->level % 2; - mt = mtext_from_data (text, length, MTEXT_FORMAT_UTF_8); - nchars = mtext_len (mt); - if (debug_level > 0) - { - g_debug ("shape \"U+%04X\"", mtext_ref_char (mt, 0)); - } - - offsets = alloca (sizeof (int) * nchars); - g_return_if_fail (offsets != NULL); - for (i = 0, p = text; i < nchars; i++, p = g_utf8_next_char (p)) + offsets = g_newa (int, length); + for (i = 0, p = text, pend = text + length; p < pend; + i++, p = g_utf8_next_char (p)) offsets[i] = p - text; + gstring.used = i; - font = m17n_fc_get_font (pango_font); - g_return_if_fail (font != NULL); - - mtext_put_prop (mt, 0, nchars, Mfont, font); -#if 0 - if (language != Mnil) - mtext_put_prop (mt, 0, nchars, Mlanguage, language); -#endif - - control.enable_bidi = 1; - m_glyphs = alloca (sizeof (MDrawGlyph) * nchars * 2); - g_return_if_fail (m_glyphs != NULL); - if (mdraw_glyph_list (frame, mt, 0, nchars, &control, m_glyphs, - nchars * 2, &nglyphs) < 0) - { - m_glyphs = alloca (sizeof (MDrawGlyph) * nglyphs); - g_return_if_fail (m_glyphs != NULL); - mdraw_glyph_list (frame, mt, 0, nchars, &control, m_glyphs, - nglyphs, &nglyphs); - } - - pango_glyph_string_set_size (glyphs, nglyphs); - - for (i = 0, g = glyphs->glyphs; i < nglyphs; i++, g++) + /* Try at most three times, each time with larger GSTRING->glyphs. */ + gstring.allocated = length; + for (i = 0; i < 3; i++, gstring.allocated += length) { - if (m_glyphs[i].glyph_code >= 0) + int result = shape_text (text, offsets, &gstring, font_info, glyphs); + + if (result != -2) { - g->glyph = m_glyphs[i].glyph_code; - g->geometry.x_offset = m_glyphs[i].x_off * PANGO_SCALE; - g->geometry.y_offset = m_glyphs[i].y_off * PANGO_SCALE; - g->geometry.width = m_glyphs[i].x_advance * PANGO_SCALE; + g_return_if_fail (result >= 0); + break; } - else - { - int c = mtext_ref_char (mt, m_glyphs[i].from); - MSymbol category = mchar_get_prop (c, Mcategory); - PangoRectangle logical_rect; - - if (category == MZs) - { - g->glyph = 0; - g->geometry.width = m_glyphs[i].x_advance * PANGO_SCALE; - } - else if (category == MCf) - { - g->glyph = 0; - g->geometry.width = 0; - } - else - { - g->glyph = (pango_fc_font_get_unknown_glyph - (PANGO_FC_FONT (pango_font), c)); - pango_font_get_glyph_extents (pango_font, g->glyph, NULL, - &logical_rect); - g->geometry.width = logical_rect.width; - } - g->geometry.x_offset = 0; - g->geometry.y_offset = 0; - } - g->attr.is_cluster_start - = (i == 0 - || m_glyphs[i - 1].from != m_glyphs[i].from); - glyphs->log_clusters[i] = offsets[m_glyphs[i].from]; } - - m17n_object_unref (mt); } -/* Check if PANGO_FONT is suitable for the character WC. */ +#if 0 + +/* Check if FONT is suitable for the character WC. For the moment, + this is commented out because even if it returns + PANGO_COVERAGE_NONE, the other engine will use the font. In + addition, the caller doesn't handle PANGO_COVERAGE_APPROXIMATE and + PANGO_COVERAGE_FALLBACK well. */ static PangoCoverageLevel m17n_fc_engine_covers (PangoEngineShape *engine, - PangoFont *pango_font, - PangoLanguage *pango_language, + PangoFont *font, + PangoLanguage *language, gunichar wc) { - static gunichar last_wc = 0; - /* Symbols for character property `script'. */ - static MSymbol Mlatin, Mcommon, Minherited; - PangoCoverage *coverage; - PangoCoverageLevel result; - MSymbol script, language; - MPlist *spec_list, *p; - MFont *font; - - if (! Mlatin) - { - Mlatin = msymbol ("latin"); - Mcommon = msymbol ("common"); - Minherited = msymbol ("inherited"); - } - -#if 1 - return PANGO_COVERAGE_EXACT; -#else - if (debug_level > 0 && wc != last_wc) - { - g_debug ("covers for U+%04X", wc); - last_wc = wc; - } + FontInfo *font_info = get_font_info (font); + MFLT *flt = mflt_find (wc, (MFLTFont *) font_info); + const char *lang = pango_language_to_string (language); - coverage = pango_font_get_coverage (pango_font, pango_language); - result = pango_coverage_get (coverage, wc); - pango_coverage_unref (coverage); - - if (result == PANGO_COVERAGE_NONE) + if (! flt) { - if (debug_level > 0) - g_debug (" %s none", m17n_fc_get_family (pango_font)); - return result; - } - - language = m17n_fc_get_language (pango_language); - if (wc < 0x100) - script = Mlatin; - else - { - script = mchar_get_prop ((int) wc, Mscript); - if (script == Mcommon || script == Minherited) - script = mchar_get_prop ((int) wc, msymbol ("block")); + if (debug_level) + g_debug (" %04X (%s/%s): no FLT\n", wc, lang, + msymbol_name (font_info->font.family)); + return PANGO_COVERAGE_NONE; } + if (debug_level) + g_debug (" %04X (%s/%s): FLT %s found\n", wc, lang, + msymbol_name (font_info->font.family), mflt_name (flt)); + return PANGO_COVERAGE_EXACT; +} - font = m17n_fc_get_font (pango_font); - spec_list = m17n_fc_lookup_fontset (script, language); - - result = PANGO_COVERAGE_NONE; - for (p = spec_list; mplist_key (p) != Mnil; p = mplist_next (p)) - if (mfont_match_p (font, mplist_value (p))) - { - result = PANGO_COVERAGE_EXACT; - break; - } - m17n_object_unref (spec_list); - if (debug_level > 0) - g_debug (" (%s,%s): %s %s", - (script ? msymbol_name (script) : ""), - (language ? msymbol_name (language) : ""), - m17n_fc_get_family (pango_font), - result == PANGO_COVERAGE_EXACT ? "exact" : "none"); - - return result; #endif -} static void m17n_engine_fc_class_init (PangoEngineShapeClass *class) { class->script_shape = m17n_fc_engine_shape; +#if 0 class->covers = m17n_fc_engine_covers; +#endif } PANGO_ENGINE_SHAPE_DEFINE_TYPE (M17NEngineFc, m17n_engine_fc, @@ -530,15 +636,14 @@ void PANGO_MODULE_ENTRY(init) (GTypeModule *module) { m17n_engine_fc_register_type (module); - M17N_INIT (); - init_module (); + if (getenv ("PANGO_M17N_DEBUG") != NULL) + debug_level = 1; } void PANGO_MODULE_ENTRY(exit) (void) { - fini_module (); M17N_FINI (); } -- 1.7.10.4