/* font-ft.c -- FreeType interface sub-module.
- Copyright (C) 2003, 2004, 2007
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H15PRO112
#ifdef HAVE_OTF
static OTF *invalid_otf = (OTF *) "";
+static OTF *get_otf (MFLTFont *font, FT_Face *ft_face);
#endif /* HAVE_OTF */
typedef struct
} while (0)
-static MPlist *ft_list_family (MSymbol, int);
+static MPlist *ft_list_family (MSymbol, int, int);
static void
free_ft_rfont (void *object)
file = msymbol (filename);
if (family != last_family)
{
- pl = MPLIST_PLIST (ft_list_family (family, 0));
+ pl = MPLIST_PLIST (ft_list_family (family, 0, 1));
last_family = family;
}
ft_info = mplist_get (pl, file);
MPlist *plist = NULL, *pl, *p;
if (! ft_font_list)
- ft_list_family (Mnil, 0);
+ ft_list_family (Mnil, 0, 1);
if (mt)
{
scan all fonts and return ft_font_list. */
static MPlist *
-ft_list_family (MSymbol family, int check_generic)
+ft_list_family (MSymbol family, int check_generic, int check_alias)
{
MPlist *plist;
#ifdef HAVE_FONTCONFIG
MPLIST_DO (plist, ft_font_list)
{
if (! MPLIST_VAL (plist))
- ft_list_family (MPLIST_KEY (plist), 0);
+ ft_list_family (MPLIST_KEY (plist), 0, 1);
}
all_fonts_scaned = 1;
}
FcChar8 *fam8;
if (family != generic)
- plist = ft_list_family (generic, 1);
+ plist = ft_list_family (generic, 1, 1);
else
{
fam = MSYMBOL_NAME (family);
family = msymbol (buf);
if (msymbol_get (family, Mgeneric_family))
break;
- pl = ft_list_family (family, 0);
+ pl = ft_list_family (family, 0, 1);
if (! pl)
continue;
MPLIST_DO (pl, MPLIST_PLIST (pl))
plist = ft_font_list;
}
}
- else
+ else if (check_alias)
{
/* Check if there exist an alias. */
pl = mplist ();
FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
STRDUP_LOWER (buf, bufsize, fam);
sym = msymbol (buf);
- p = MPLIST_PLIST (ft_list_family (sym, 0));
+ p = MPLIST_PLIST (ft_list_family (sym, 0, 0));
if (! MPLIST_TAIL_P (p))
MPLIST_DO (p, p)
mplist_push (pl, Mt, MPLIST_VAL (p));
}
}
}
+ else
+ {
+ pl = mplist ();
+ plist = mplist_add (ft_font_list, family, pl);
+ }
#else /* not HAVE_FONTCONFIG */
}
}
if (cap->features[MFONT_OTT_GSUB].nfeatures
- && cap->features[MFONT_OTT_GSUB].tags[0]
&& (OTF_check_features
(ft_info->otf, 1,
cap->script_tag, cap->langsys_tag,
cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
return -1;
if (cap->features[MFONT_OTT_GPOS].nfeatures
- && cap->features[MFONT_OTT_GPOS].tags[0]
&& (OTF_check_features
(ft_info->otf, 0,
cap->script_tag, cap->langsys_tag,
family = msymbol (buf);
if (msymbol_get (family, Mgeneric_family))
continue;
- plist = MPLIST_PLIST (ft_list_family (family, 0));
+ plist = MPLIST_PLIST (ft_list_family (family, 0, 1));
MPLIST_DO (plist, plist)
mplist_add (ft_default_list, family, MPLIST_VAL (plist));
}
{
MPlist *plist, *pl;
- MPLIST_DO (plist, ft_list_family (Mnil, 0))
+ MPLIST_DO (plist, ft_list_family (Mnil, 0, 1))
{
pl = MPLIST_PLIST (plist);
if (! MPLIST_TAIL_P (pl))
STRDUP_LOWER (buf, bufsize, fam);
family = msymbol (buf);
- pl = ft_list_family (family, 0);
+ pl = ft_list_family (family, 0, 1);
MPLIST_DO (pl, MPLIST_PLIST (pl))
{
MFontFT *ft_info = MPLIST_VAL (pl);
{
MPlist *pl, *p;
- MPLIST_DO (pl, ft_list_family (Mnil, 0))
+ MPLIST_DO (pl, ft_list_family (Mnil, 0, 1))
{
MPLIST_DO (p, MPLIST_PLIST (pl))
{
MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
if (family)
- plist = MPLIST_PLIST (ft_list_family (family, 1));
+ plist = MPLIST_PLIST (ft_list_family (family, 1, 1));
else
plist = ft_list_default ();
if (MPLIST_TAIL_P (plist))
ft_rfont->ft_face = ft_face;
ft_rfont->charmap_list = charmap_list;
MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
+ rfont->id = ft_info->font.file;
rfont->spec = *font;
rfont->spec.type = MFONT_TYPE_REALIZED;
rfont->spec.property[MFONT_REGISTRY] = reg;
goto done;
family = FONT_PROPERTY (font, MFONT_FAMILY);
if (family != Mnil
- && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
+ && (family_list = MPLIST_PLIST (ft_list_family (family, 1, 1)))
&& MPLIST_TAIL_P (family_list))
goto done;
if (font->capability != Mnil)
{
/* No restriction. Get all fonts. */
pl = mplist ();
- MPLIST_DO (family_list, ft_list_family (Mnil, 0))
+ MPLIST_DO (family_list, ft_list_family (Mnil, 0, 1))
{
MPLIST_DO (p, MPLIST_PLIST (family_list))
mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
ft_rfont->ft_face = ft_face;
ft_rfont->face_encapsulated = 1;
- MDEBUG_DUMP (" [FONT-FT] encapsulating ", (char *) ft_face->family_name,);
+ MDEBUG_PRINT1 (" [FONT-FT] encapsulating %s", (char *) ft_face->family_name);
MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
+ rfont->id = ft_info->font.file;
rfont->font = (MFont *) ft_info;
rfont->info = ft_rfont;
rfont->fontp = ft_face;
ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
{
#ifdef HAVE_OTF
- MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
- MFontFT *ft_info = (MFontFT *) rfont->font;
- OTF *otf;
OTF_Tag *tags;
int i, n, negative;
+ OTF *otf = get_otf (font, NULL);
- if (ft_info->otf == invalid_otf)
- goto not_otf;
- otf = ft_info->otf;
if (! otf)
- {
- MRealizedFontFT *ft_rfont = rfont->info;
-
-#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
- otf = OTF_open_ft_face (ft_rfont->ft_face);
-#else
- otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
-#endif
- if (! otf)
- {
- ft_info->otf = invalid_otf;
- goto not_otf;
- }
- ft_info->otf = otf;
- }
-
+ goto not_otf;
for (i = 0; i < 2; i++)
{
if (! spec->features[i])
return 0;
}
return 1;
-#endif /* HAVE_OTF */
not_otf:
+#endif /* HAVE_OTF */
return ((! spec->features[0] || spec->features[0][0] == 0xFFFFFFFF)
&& (! spec->features[1] || spec->features[1][0] == 0xFFFFFFFF));
}
#ifdef HAVE_OTF
+static OTF *
+get_otf (MFLTFont *font, FT_Face *ft_face)
+{
+ MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+ MFontFT *ft_info = (MFontFT *) rfont->font;
+ MRealizedFontFT *ft_rfont = rfont->info;
+ OTF *otf = ft_info->otf;
+
+ if (! otf)
+ {
+#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
+ otf = OTF_open_ft_face (ft_rfont->ft_face);
+#else
+ otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
+#endif
+ if (! otf || OTF_get_table (otf, "head") < 0)
+ otf = invalid_otf;
+ ft_info->otf = otf;
+ }
+ if (ft_face)
+ *ft_face = ft_rfont->ft_face;
+ return (otf == invalid_otf ? NULL : otf);
+}
+
#define DEVICE_DELTA(table, size) \
(((size) >= (table).StartSize && (size) <= (table).EndSize) \
? (table).DeltaValue[(size) - (table).StartSize] << 6 \
MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
{
int len = to - from;
- int i, j, gidx;
- MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
- MRealizedFontFT *ft_rfont = rfont->info;
- MFontFT *ft_info = (MFontFT *) rfont->font;
#ifdef HAVE_OTF
+ int i, j, gidx;
MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
- MGlyph *out_glyphs = (MGlyph *) (out->glyphs);
+ MGlyph *out_glyphs = out ? (MGlyph *) (out->glyphs) : NULL;
OTF *otf;
+ FT_Face face;
OTF_GlyphString otf_gstring;
OTF_Glyph *otfg;
char script[5], *langsys = NULL;
char *gsub_features = NULL, *gpos_features = NULL;
+ unsigned int tag;
if (len == 0)
return from;
- if (ft_info->otf == invalid_otf)
- goto simple_copy;
- otf = ft_info->otf;
+ otf = get_otf (font, &face);
if (! otf)
- {
- MRealizedFontFT *ft_rfont = rfont->info;
-
-#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
- otf = OTF_open_ft_face (ft_rfont->ft_face);
-#else
- otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
-#endif
- if (! otf)
- {
- ft_info->otf = invalid_otf;
- goto simple_copy;
- }
- ft_info->otf = otf;
- }
-
- if (OTF_get_table (otf, "head") < 0)
- {
- OTF_close (otf);
- ft_info->otf = invalid_otf;
- goto simple_copy;
- }
-
+ goto simple_copy;
OTF_tag_name (spec->script, script);
if (spec->langsys)
{
{
char *p;
- if (spec->features[i] && spec->features[i][0] != 0xFFFFFFFF)
+ if (spec->features[i])
{
for (j = 0; spec->features[i][j]; j++);
if (i == 0)
memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
for (i = 0; i < len; i++)
{
- otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c;
+ otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c & 0x11FFFF;
otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
}
OTF_drive_gdef (otf, &otf_gstring);
- gidx = out->used;
+ gidx = out ? out->used : from;
if (gsub_features)
{
- if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
- < 0)
+ OTF_Feature *features;
+ MGlyph *g;
+
+ if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
+ gsub_features) < 0)
goto simple_copy;
- if (out->allocated < out->used + otf_gstring.used)
- return -2;
- for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
+ features = otf->gsub->FeatureList.Feature;
+ if (out)
{
- MGlyph *g = out_glyphs + out->used;
- int j;
- int min_from, max_to;
-
- *g = in_glyphs[from + otfg->f.index.from];
- min_from = g->g.from, max_to = g->g.to;
- g->g.c = 0;
- for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
- if (in_glyphs[from + j].g.code == otfg->glyph_id)
- {
- g->g.c = in_glyphs[from + j].g.c;
- break;
- }
- for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
+ if (out->allocated < gidx + otf_gstring.used)
+ return -2;
+ for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
+ i < otf_gstring.used; i++, otfg++, g++, out->used++)
{
- if (min_from > in_glyphs[from + j].g.from)
- min_from = in_glyphs[from + j].g.from;
- if (max_to < in_glyphs[from + j].g.to)
- max_to = in_glyphs[from + j].g.to;
+ int feature_idx = otfg->positioning_type >> 4;
+ int j;
+ int min_from, max_to;
+
+ *g = in_glyphs[from + otfg->f.index.from];
+ min_from = g->g.from, max_to = g->g.to;
+ g->g.c = 0;
+ for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
+ if (in_glyphs[from + j].g.code == otfg->glyph_id)
+ {
+ g->g.c = in_glyphs[from + j].g.c;
+ break;
+ }
+ if (feature_idx)
+ {
+ tag = features[feature_idx - 1].FeatureTag;
+ tag = PACK_OTF_TAG (tag);
+ g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
+ }
+ for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
+ {
+ if (min_from > in_glyphs[from + j].g.from)
+ min_from = in_glyphs[from + j].g.from;
+ if (max_to < in_glyphs[from + j].g.to)
+ max_to = in_glyphs[from + j].g.to;
+ }
+ if (g->g.code != otfg->glyph_id)
+ {
+ g->g.code = otfg->glyph_id;
+ g->g.measured = 0;
+ }
+ g->g.from = min_from, g->g.to = max_to;
}
- if (g->g.code != otfg->glyph_id)
+ }
+ else
+ {
+ for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
+ i++, otfg++)
{
- g->g.code = otfg->glyph_id;
- g->g.measured = 0;
+ int feature_idx = otfg->positioning_type >> 4;
+
+ if (feature_idx)
+ {
+ tag = features[feature_idx - 1].FeatureTag;
+ tag = PACK_OTF_TAG (tag);
+ for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
+ {
+ g = in_glyphs + (from + j);
+ g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
+ }
+ }
}
- g->g.from = min_from, g->g.to = max_to;
- out->used++;
}
}
- else
+ else if (out)
{
- if (out->allocated < out->used + len)
+ if (out->allocated < gidx + len)
return -2;
for (i = 0; i < len; i++)
out_glyphs[out->used++] = in_glyphs[from + i];
if (gpos_features)
{
- FT_Face face;
- MGlyph *base = NULL, *mark = NULL, *g;
- int x_ppem, y_ppem, x_scale, y_scale;
+ OTF_Feature *features;
+ MGlyph *g;
- if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
- < 0)
+ if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
+ gpos_features) < 0)
return to;
-
- face = ft_rfont->ft_face;
- x_ppem = face->size->metrics.x_ppem;
- y_ppem = face->size->metrics.y_ppem;
- x_scale = face->size->metrics.x_scale;
- y_scale = face->size->metrics.y_scale;
-
- for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
- i < otf_gstring.used; i++, otfg++, g++)
+ features = otf->gpos->FeatureList.Feature;
+ if (out)
{
- MGlyph *prev;
-
- if (! otfg->glyph_id)
- continue;
- switch (otfg->positioning_type)
+ MGlyph *base = NULL, *mark = NULL;
+ int x_ppem = face->size->metrics.x_ppem;
+ int y_ppem = face->size->metrics.y_ppem;
+ int x_scale = face->size->metrics.x_scale;
+ int y_scale = face->size->metrics.y_scale;
+
+ for (i = j = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
+ i < otf_gstring.used; i++, otfg++)
{
- case 0:
- break;
- case 1: /* Single */
- case 2: /* Pair */
- {
- int format = otfg->f.f1.format;
-
- if (format & OTF_XPlacement)
- adjustment[i].xoff
- = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
- if (format & OTF_XPlaDevice)
- adjustment[i].xoff
- += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
- if (format & OTF_YPlacement)
- adjustment[i].yoff
- = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
- if (format & OTF_YPlaDevice)
- adjustment[i].yoff
- -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
- if (format & OTF_XAdvance)
- adjustment[i].xadv
- += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
- if (format & OTF_XAdvDevice)
- adjustment[i].xadv
- += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
- if (format & OTF_YAdvance)
- adjustment[i].yadv
- += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
- if (format & OTF_YAdvDevice)
- adjustment[i].yadv
- += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
- adjustment[i].set = 1;
- }
- break;
- case 3: /* Cursive */
- /* Not yet supported. */
- break;
- case 4: /* Mark-to-Base */
- case 5: /* Mark-to-Ligature */
- if (! base)
- break;
- prev = base;
- goto label_adjust_anchor;
- default: /* i.e. case 6 Mark-to-Mark */
- if (! mark)
- break;
- prev = mark;
+ MGlyph *prev;
+ int adjust_idx = otfg->glyph_id ? j : j - 1;
+ int feature_idx = otfg->positioning_type >> 4;
- label_adjust_anchor:
- {
- int base_x, base_y, mark_x, mark_y;
- int this_from, this_to;
-
- base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
- base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
- mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
- mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
-
- if (otfg->f.f4.base_anchor->AnchorFormat != 1)
- adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
- x_ppem, y_ppem, &base_x, &base_y);
- if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
- adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
- x_ppem, y_ppem, &mark_x, &mark_y);
- adjustment[i].xoff = (base_x - mark_x);
- adjustment[i].yoff = - (base_y - mark_y);
- adjustment[i].back = (g - prev);
- adjustment[i].xadv = 0;
- adjustment[i].advance_is_absolute = 1;
- adjustment[i].set = 1;
- this_from = g->g.from;
- this_to = g->g.to;
- for (j = 0; prev + j < g; j++)
+ if (feature_idx)
+ {
+ tag = features[feature_idx - 1].FeatureTag;
+ tag = PACK_OTF_TAG (tag);
+ g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
+ }
+ switch (otfg->positioning_type & 0xF)
+ {
+ case 0:
+ break;
+ case 1: /* Single */
+ case 2: /* Pair */
{
- if (this_from > prev[j].g.from)
- this_from = prev[j].g.from;
- if (this_to < prev[j].g.to)
- this_to = prev[j].g.to;
+ int format = otfg->f.f1.format;
+
+ if (format & OTF_XPlacement)
+ adjustment[adjust_idx].xoff
+ += otfg->f.f1.value->XPlacement * x_scale / 0x10000;
+ if (format & OTF_XPlaDevice)
+ adjustment[adjust_idx].xoff
+ += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
+ if (format & OTF_YPlacement)
+ adjustment[adjust_idx].yoff
+ -= otfg->f.f1.value->YPlacement * y_scale / 0x10000;
+ if (format & OTF_YPlaDevice)
+ adjustment[adjust_idx].yoff
+ -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
+ if (format & OTF_XAdvance)
+ adjustment[adjust_idx].xadv
+ += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
+ if (format & OTF_XAdvDevice)
+ adjustment[adjust_idx].xadv
+ += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
+ if (format & OTF_YAdvance)
+ adjustment[adjust_idx].yadv
+ += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
+ if (format & OTF_YAdvDevice)
+ adjustment[adjust_idx].yadv
+ += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
+ adjustment[adjust_idx].set = 1;
}
- for (; prev <= g; prev++)
+ break;
+ case 3: /* Cursive */
+ /* Not yet supported. */
+ break;
+ case 4: /* Mark-to-Base */
+ case 5: /* Mark-to-Ligature */
+ if (! base)
+ break;
+ prev = base;
+ goto label_adjust_anchor;
+ default: /* i.e. case 6 Mark-to-Mark */
+ if (! mark)
+ break;
+ prev = mark;
+
+ label_adjust_anchor:
{
- prev->g.from = this_from;
- prev->g.to = this_to;
+ int base_x, base_y, mark_x, mark_y;
+ int this_from, this_to;
+ int k;
+
+ base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
+ base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
+ mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
+ mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
+
+ if (otfg->f.f4.base_anchor->AnchorFormat != 1)
+ adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
+ x_ppem, y_ppem, &base_x, &base_y);
+ if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
+ adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
+ x_ppem, y_ppem, &mark_x, &mark_y);
+ adjustment[adjust_idx].xoff = base_x - mark_x;
+ adjustment[adjust_idx].yoff = - (base_y - mark_y);
+ adjustment[adjust_idx].back = (g - prev);
+ adjustment[adjust_idx].xadv = 0;
+ adjustment[adjust_idx].advance_is_absolute = 1;
+ adjustment[adjust_idx].set = 1;
+ this_from = g->g.from;
+ this_to = g->g.to;
+ for (k = 0; prev + k < g; k++)
+ {
+ if (this_from > prev[k].g.from)
+ this_from = prev[k].g.from;
+ if (this_to < prev[k].g.to)
+ this_to = prev[k].g.to;
+ }
+ for (; prev <= g; prev++)
+ {
+ prev->g.from = this_from;
+ prev->g.to = this_to;
+ }
}
- }
+ }
+ if (otfg->glyph_id)
+ {
+ if (otfg->GlyphClass == OTF_GlyphClass0)
+ base = mark = g;
+ else if (otfg->GlyphClass == OTF_GlyphClassMark)
+ mark = g;
+ else
+ base = g;
+ j++, g++;
+ }
}
- if (otfg->GlyphClass == OTF_GlyphClass0)
- base = mark = g;
- else if (otfg->GlyphClass == OTF_GlyphClassMark)
- mark = g;
- else
- base = g;
+ }
+ else
+ {
+ for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
+ i++, otfg++)
+ if (otfg->positioning_type & 0xF)
+ {
+ int feature_idx = otfg->positioning_type >> 4;
+
+ if (feature_idx)
+ {
+ tag = features[feature_idx - 1].FeatureTag;
+ tag = PACK_OTF_TAG (tag);
+ for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
+ {
+ g = in_glyphs + (from + j);
+ g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
+ }
+ }
+ }
}
}
+
free (otf_gstring.glyphs);
return to;
simple_copy:
-#endif /* HAVE_OTF */
- if (out->allocated < out->used + len)
- return -2;
- font->get_metrics (font, in, from, to);
- memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
- sizeof (MGlyph) * len);
- out->used += len;
if (otf_gstring.glyphs)
free (otf_gstring.glyphs);
+#endif /* HAVE_OTF */
+ if (out)
+ {
+ if (out->allocated < out->used + len)
+ return -2;
+ font->get_metrics (font, in, from, to);
+ memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
+ sizeof (MGlyph) * len);
+ out->used += len;
+ }
return to;
}
+static int
+ft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
+ MFLTGlyphString *in, int from, int to)
+{
+ return ft_drive_otf (font, spec, in, from, to, NULL, NULL);
+}
+
+
+#ifdef HAVE_OTF
+static unsigned char *iterate_bitmap;
+
+static int
+iterate_callback (OTF *otf, const char *feature, unsigned glyph_id)
+{
+ if (glyph_id <= otf->cmap->max_glyph_id)
+ iterate_bitmap[glyph_id / 8] |= 1 << (glyph_id % 8);
+ return 0;
+}
+
+static int
+ft_iterate_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
+ int from, int to, unsigned char *table)
+{
+ OTF *otf = get_otf (font, NULL);
+ char id[13];
+ int bmp_size;
+ unsigned char *bitmap = NULL;
+ int i, j;
+ char script[5], *langsys = NULL;
+
+ if (! otf)
+ return -1;
+ if (OTF_get_table (otf, "cmap") < 0)
+ return -1;
+ if (! spec->features[0])
+ return -1;
+ strcpy (id, "feature-");
+ id[12] = '\0';
+ OTF_tag_name (spec->script, script);
+ if (spec->langsys)
+ {
+ langsys = alloca (5);
+ OTF_tag_name (spec->langsys, langsys);
+ }
+ bmp_size = (otf->cmap->max_glyph_id / 8) + 1;
+ for (i = 0; spec->features[0][i]; i++)
+ {
+ unsigned char *bmp;
+
+ OTF_tag_name (spec->features[0][i], id + 8);
+ bmp = OTF_get_data (otf, id);
+ if (! bmp)
+ {
+ iterate_bitmap = bmp = calloc (bmp_size, 1);
+ OTF_iterate_gsub_feature (otf, iterate_callback,
+ script, langsys, id + 8);
+ OTF_put_data (otf, id, bmp, free);
+ }
+ if (i == 0 && ! spec->features[0][1])
+ /* Single feature */
+ bitmap = bmp;
+ else
+ {
+ if (! bitmap)
+ {
+ bitmap = alloca (bmp_size);
+ memcpy (bitmap, bmp, bmp_size);
+ }
+ else
+ {
+ int j;
+
+ for (j = 0; j < bmp_size; j++)
+ bitmap[j] &= bmp[j];
+ }
+ }
+ }
+ for (i = 0; i < bmp_size; i++)
+ if (bitmap[i])
+ {
+ for (j = 0; j < 8; j++)
+ if (bitmap[i] & (1 << j))
+ {
+ int c = OTF_get_unicode (otf, (i * 8) + j);
+
+ if (c >= from && c <= to)
+ table[c - from] = 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+
\f
/* Internal API */
MFontDriver mfont__ft_driver =
{ ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
ft_render, ft_list, ft_list_family_names, ft_check_capability,
- ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf };
+ ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf, ft_try_otf,
+#ifdef HAVE_OTF
+ ft_iterate_otf_feature
+#endif /* HAVE_OTF */
+ };
int
mfont__ft_init ()