+void
+setup_features (PangoOTTableType type, FontInfoPango *font_info,
+ MFLTOtfSpec *spec, FeatureInfo *info)
+{
+ int count, preordered;
+ unsigned int *features;
+ guint script, langsys;
+ guint req_feature, index;
+ guint *feature_list;
+ int i, j, k;
+ int err;
+ FT_Face face;
+ PangoOTInfo *ot_info;
+
+ face = pango_fc_font_lock_face (font_info->pango_font);
+ ot_info = pango_ot_info_get (face);
+ pango_fc_font_unlock_face (font_info->pango_font);
+
+ if (! pango_ot_info_find_script (ot_info, type, spec->script, &script))
+ return;
+ if (spec->langsys)
+ {
+ if (! pango_ot_info_find_language (ot_info, type, script,
+ spec->langsys,
+ &langsys, &req_feature))
+ return;
+ }
+ else
+ {
+ langsys = PANGO_OT_DEFAULT_LANGUAGE;
+ req_feature = 0xFFFF;
+ }
+ if (type == PANGO_OT_TABLE_GSUB)
+ {
+ count = spec->gsub_count;
+ features = spec->gsub;
+ }
+ else
+ {
+ count = spec->gpos_count;
+ features = spec->gpos;
+ }
+ feature_list = NULL;
+ for (preordered = 0; preordered < count; preordered++)
+ if (features[preordered] == 0)
+ {
+ feature_list = pango_ot_info_list_features (ot_info, type, 0,
+ script, langsys);
+ if (! feature_list)
+ return;
+ break;
+ }
+ if (feature_list)
+ for (i = 0; feature_list[i]; i++);
+ else
+ i = preordered;
+ info->indices = malloc (sizeof (guint) * ((req_feature != 0xFFFF) + i));
+ i = 0;
+ if (req_feature != 0xFFFF)
+ info->indices[i++] = req_feature;
+ for (j = 0; j < preordered; j++)
+ if (pango_ot_info_find_feature (ot_info, type, features[j],
+ script, langsys, &index))
+ info->indices[i++] = index;
+ if (feature_list)
+ for (j = 0; feature_list[j]; j++)
+ {
+ for (k = preordered + 1; k < count; k++)
+ if (feature_list[j] == features[k])
+ break;
+ if (k == count
+ && pango_ot_info_find_feature (ot_info, type, feature_list[j],
+ script, langsys, &index))
+ info->indices[i++] = index;
+ }
+ info->count = i;
+ info->ruleset = pango_ot_ruleset_new (ot_info);
+ for (i = 0; i < info->count; i++)
+ pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
+ PANGO_OT_ALL_GLYPHS);
+}
+
+GsubGposInfo *
+setup_otf_spec (FontInfoPango *font_info, MFLTOtfSpec *spec)
+{
+ GsubGposInfo *ginfo;
+
+ if (spec->gsub_count + spec->gpos_count == 0)
+ return NULL;
+ ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
+ if (ginfo)
+ return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
+ ginfo = calloc (1, sizeof (GsubGposInfo));
+ mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
+ setup_features (PANGO_OT_TABLE_GSUB, font_info, spec, &(ginfo->gsub));
+ setup_features (PANGO_OT_TABLE_GPOS, font_info, spec, &(ginfo->gpos));
+ return ginfo;
+}
+
+int
+drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
+ MFLTGlyphString *in, int from, int to,
+ MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
+{
+ FontInfoPango *font_info = (FontInfoPango *) font;
+ PangoOTBuffer *buffer;
+ GsubGposInfo *ginfo;
+ 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);
+ ginfo = setup_otf_spec (font_info, spec);
+ if (! ginfo)
+ goto simple_copy;
+ if (ginfo->gsub.count > 0)
+ pango_ot_ruleset_substitute (ginfo->gsub.ruleset, buffer);
+ if (ginfo->gpos.count > 0)
+ pango_ot_ruleset_position (ginfo->gpos.ruleset, buffer);
+ glyphs = pango_glyph_string_new ();
+ pango_ot_buffer_output (buffer, glyphs);
+ for (i = 0; i < glyphs->num_glyphs; i++)
+ {
+ 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->xoff = glyph_info->geometry.x_offset;
+ g->yoff = glyph_info->geometry.y_offset;
+ g->xadv = glyph_info->geometry.width;
+ g->yadv = 0;
+ adjustment[i].set = 0;
+ }
+ 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;
+}
+
+
+MFLTFont *
+open_font (char *fontname, char **err)
+{
+ FontInfoPango *font_info = NULL;
+ PangoFontMap *fontmap;
+ PangoContext *context;
+ PangoFontDescription *desc;
+ PangoFont *pango_font;
+ char *family;
+ int size;
+ double pango_size;
+
+ if (parse_font_name (fontname, &family, &size, err) < 0)
+ return NULL;
+ desc = pango_font_description_new ();
+ pango_font_description_set_family (desc, family);
+ free (family);
+ pango_size = size * PANGO_SCALE;
+ pango_font_description_set_absolute_size (desc, pango_size);
+
+ fontmap = pango_ft2_font_map_new ();
+ context = pango_context_new ();
+ pango_context_set_font_map (context, fontmap);
+ pango_font = pango_context_load_font (context, desc);
+ pango_font_description_free (desc);
+ if (pango_font)
+ {
+ font_info = calloc (1, sizeof (FontInfoPango));
+ font_info->fontmap = fontmap;
+ font_info->context = context;
+ font_info->pango_font = PANGO_FC_FONT (pango_font);
+ }
+ else
+ {
+ g_object_unref (context);
+ g_object_unref (fontmap);
+ }
+ return (MFLTFont *) font_info;
+}
+
+void
+close_font (MFLTFont *font)
+{
+ FontInfoPango *font_info = (FontInfoPango *) font;
+
+ g_object_unref (font_info->context);
+ g_object_unref (font_info->fontmap);
+}
+
+int
+flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
+{
+ MFLTGlyphString gstring;
+ int len = to - from;
+ int i;
+
+ memset (&gstring, 0, sizeof (MFLTGlyphString));
+ gstring.glyph_size = sizeof (MFLTGlyph);
+ gstring.allocated = len * 2;
+ gstring.glyphs = alloca (sizeof (MFLTGlyph) * gstring.allocated);
+ for (i = 0; i < len; i++)
+ gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
+ gstring.used = len;
+ return mflt_run (&gstring, 0, len, font, msymbol (flt_name));
+}
+