/* 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
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307, USA. */
+#include <config.h>
#include <string.h>
#include <stdlib.h>
+#include <ctype.h>
+#include <pango/pango-ot.h>
#include <pango/pango-engine.h>
-#include <pango/pango-utils.h>
#include <pango/pangofc-font.h>
-#include <m17n-gui.h>
-#include <m17n-misc.h>
-
#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;
{ PANGO_SCRIPT_CANADIAN_ABORIGINAL, "*" },
{ PANGO_SCRIPT_YI, "*" },
-#ifdef PANGO_SCRIPT_BRAILLE
{ PANGO_SCRIPT_BRAILLE, "*" },
{ PANGO_SCRIPT_CYPRIOT, "*" },
{ PANGO_SCRIPT_LIMBU, "*" },
{ 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, "*" },
{ PANGO_SCRIPT_SYLOTI_NAGRI, "*" },
{ PANGO_SCRIPT_OLD_PERSIAN, "*" },
{ PANGO_SCRIPT_KHAROSHTHI, "*" },
-#endif /* PANGO_SCRIPT_NEW_TAI_LUE */
-
- { PANGO_SCRIPT_UNKNOWN, "*" },
-
{ PANGO_SCRIPT_COMMON, "" }
};
}
};
-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 <m17n-flt.h>
+#include <m17n-misc.h>
-/* 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,
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 ();
}