/* ftfont.c -- FreeType font driver.
- Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
- Copyright (C) 2006, 2007, 2008
+ Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2009
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H13PRO009
#include "character.h"
#include "charset.h"
#include "coding.h"
+#include "composite.h"
#include "fontset.h"
#include "font.h"
#include "ftfont.h"
{
struct font font;
#ifdef HAVE_LIBOTF
- /* The following three members must be here in this order to be
+ /* The following four members must be here in this order to be
compatible with struct xftfont_info (in xftfont.c). */
int maybe_otf; /* Flag to tell if this may be OTF or not. */
OTF *otf;
{ "windows-1251", { 0x0401, 0x0490 }, "ru"},
{ "koi8-r", { 0x0401, 0x2219 }, "ru"},
{ "mulelao-1", { 0x0E81 }, "lo"},
+ { "unicode-sip", { 0x20000 }},
{ NULL }
};
Lisp_Object slot;
FcPattern *match;
FcResult result;
+ FcLangSet *langset;
family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
if (EQ (family, Qmono))
FcPatternDel (pattern, FC_FOUNDRY);
FcPatternDel (pattern, FC_FAMILY);
FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
+ if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
+ {
+ /* This is to avoid the effect of locale. */
+ langset = FcLangSetCreate ();
+ FcLangSetAdd (langset, "en");
+ FcPatternAddLangSet (pattern, FC_LANG, langset);
+ FcLangSetDestroy (langset);
+ }
FcConfigSubstitute (NULL, pattern, FcMatchPattern);
FcDefaultSubstitute (pattern);
match = FcFontMatch (NULL, pattern, &result);
else
family = Qnil;
XSETCDR (slot, family);
- err:
if (match) FcPatternDestroy (match);
+ err:
if (pattern) FcPatternDestroy (pattern);
return family;
}
FC_INDEX, FcTypeInteger, index, NULL);
objset = FcObjectSetBuild (FC_CHARSET, NULL);
fontset = FcFontList (NULL, pat, objset);
- xassert (fontset && fontset->nfont > 0);
- if (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0, &charset)
- == FcResultMatch)
+ if (fontset && fontset->nfont > 0
+ && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
+ &charset)
+ == FcResultMatch))
cache_data->fc_charset = FcCharSetCopy (charset);
else
cache_data->fc_charset = FcCharSetCreate ();
int *, int *));
static Lisp_Object ftfont_otf_capability P_ ((struct font *));
static Lisp_Object ftfont_shape P_ ((Lisp_Object));
+static int ftfont_variation_glyphs P_ ((struct font *, int c,
+ unsigned variations[256]));
struct font_driver ftfont_driver =
{
ftfont_list,
ftfont_match,
ftfont_list_family,
- NULL,
+ NULL, /* free_entity */
ftfont_open,
ftfont_close,
/* We can't draw a text without device dependent functions. */
- NULL,
- NULL,
+ NULL, /* prepare_face */
+ NULL, /* done_face */
ftfont_has_char,
ftfont_encode_char,
ftfont_text_extents,
/* We can't draw a text without device dependent functions. */
- NULL,
+ NULL, /* draw */
ftfont_get_bitmap,
- NULL,
- NULL,
- NULL,
+ NULL, /* get_bitmap */
+ NULL, /* free_bitmap */
+ NULL, /* get_outline */
ftfont_anchor_point,
#ifdef HAVE_LIBOTF
ftfont_otf_capability,
#else /* not HAVE_LIBOTF */
NULL,
#endif /* not HAVE_LIBOTF */
- NULL,
- NULL,
- NULL,
+ NULL, /* otf_drive */
+ NULL, /* start_for_frame */
+ NULL, /* end_for_frame */
#if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
- ftfont_shape
+ ftfont_shape,
#else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
- NULL
+ NULL,
#endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
+ NULL, /* check */
+#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
+ ftfont_variation_glyphs
+#else
+ NULL
+#endif
};
extern Lisp_Object QCname;
if (NILP (registry)
|| EQ (registry, Qascii_0)
|| EQ (registry, Qiso10646_1)
- || EQ (registry, Qunicode_bmp)
- || EQ (registry, Qunicode_sip))
+ || EQ (registry, Qunicode_bmp))
fc_charset_idx = -1;
else
{
{
Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
- if (CONSP (chars))
+ if (CONSP (chars) && CONSP (CDR (chars)))
{
charset = FcCharSetCreate ();
if (! charset)
FcPattern *pattern;
FcFontSet *fontset = NULL;
FcObjectSet *objset = NULL;
+ FcCharSet *charset;
+ Lisp_Object chars = Qnil;
+ FcResult result;
char otlayout[15]; /* For "otlayout:XXXX" */
struct OpenTypeSpec *otspec = NULL;
int spacing = -1;
pattern = ftfont_spec_pattern (spec, otlayout, &otspec);
if (! pattern)
return Qnil;
+ if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
+ {
+ val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
+ if (! NILP (val))
+ {
+ val = assq_no_quit (XCDR (val), Vscript_representative_chars);
+ if (CONSP (val) && VECTORP (XCDR (val)))
+ chars = XCDR (val);
+ }
+ val = Qnil;
+ }
if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
family = AREF (spec, FONT_FAMILY_INDEX);
NULL);
if (! objset)
goto err;
+ if (! NILP (chars))
+ FcObjectSetAdd (objset, FC_CHARSET);
fontset = FcFontList (NULL, pattern, objset);
- if (! fontset)
- goto err;
+ if (! fontset || fontset->nfont == 0)
+ goto finish;
#if 0
/* Need fix because this finds any fonts. */
if (fontset->nfont == 0 && ! NILP (family))
FcPatternAddString (pattern, FC_FAMILY, fam);
FcFontSetDestroy (fontset);
fontset = FcFontList (NULL, pattern, objset);
- if (fontset->nfont > 0)
+ if (fontset && fontset->nfont > 0)
break;
}
}
{
FcChar8 *this;
- if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0,
- &this) != FcResultMatch
+ if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
+ != FcResultMatch
|| ! strstr ((char *) this, otlayout))
continue;
}
continue;
}
#endif /* HAVE_LIBOTF */
+ if (VECTORP (chars))
+ {
+ int j;
+
+ if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
+ != FcResultMatch)
+ continue;
+ for (j = 0; j < ASIZE (chars); j++)
+ if (NATNUMP (AREF (chars, j))
+ && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
+ break;
+ if (j == ASIZE (chars))
+ continue;
+ }
entity = ftfont_pattern_entity (fontset->fonts[i],
AREF (spec, FONT_EXTRA_INDEX));
if (! NILP (entity))
val = Fcons (entity, val);
}
- font_add_log ("ftfont-list", spec, val);
+ val = Fnreverse (val);
goto finish;
err:
val = Qnil;
finish:
+ font_add_log ("ftfont-list", spec, val);
if (objset) FcObjectSetDestroy (objset);
if (fontset) FcFontSetDestroy (fontset);
if (pattern) FcPatternDestroy (pattern);
ftfont_match (frame, spec)
Lisp_Object frame, spec;
{
- Lisp_Object entity;
+ Lisp_Object entity = Qnil;
FcPattern *pattern, *match = NULL;
FcResult result;
char otlayout[15]; /* For "otlayout:XXXX" */
ftfont_list_family (frame)
Lisp_Object frame;
{
- Lisp_Object list;
+ Lisp_Object list = Qnil;
FcPattern *pattern = NULL;
FcFontSet *fontset = NULL;
FcObjectSet *objset = NULL;
if (! fontset)
goto finish;
- list = Qnil;
for (i = 0; i < fontset->nfont; i++)
{
FcPattern *pat = fontset->fonts[i];
ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
len = font_unparse_xlfd (entity, size, name, 256);
if (len > 0)
- ASET (font_object, FONT_NAME_INDEX, make_unibyte_string (name, len));
+ ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
len = font_unparse_fcname (entity, size, name, 256);
if (len > 0)
- ASET (font_object, FONT_FULLNAME_INDEX, make_unibyte_string (name, len));
+ ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
else
ASET (font_object, FONT_FULLNAME_INDEX,
AREF (font_object, FONT_NAME_INDEX));
}
static int
-ftfont_has_char (entity, c)
- Lisp_Object entity;
+ftfont_has_char (font, c)
+ Lisp_Object font;
int c;
{
- FcCharSet *charset = ftfont_get_fc_charset (entity);
+ if (FONT_ENTITY_P (font))
+ {
+ FcCharSet *charset = ftfont_get_fc_charset (font);
+
+ return (FcCharSetHasChar (charset, c) == FcTrue);
+ }
+ else
+ {
+ struct ftfont_info *ftfont_info;
- return (FcCharSetHasChar (charset, c) == FcTrue);
+ ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
+ return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
+ != 0);
+ }
}
static unsigned
OTF_GSUB_GPOS *gsub_gpos;
{
Lisp_Object scripts, langsyses, features, sym;
- int i, j, k;
+ int i, j, k, l;
for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
{
for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
{
- OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[k].FeatureTag);
+ l = otf_langsys->FeatureIndex[k];
+ if (l >= gsub_gpos->FeatureList.FeatureCount)
+ continue;
+ OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
features = Fcons (sym, features);
}
if (j >= 0)
sym = Qnil;
langsyses = Fcons (Fcons (sym, features), langsyses);
}
-
+
OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
scripts = Fcons (Fcons (sym, langsyses), scripts);
}
if (! otf)
return Qnil;
gsub_gpos = Fcons (Qnil, Qnil);
- if (OTF_get_table (otf, "GSUB") == 0)
+ if (OTF_get_table (otf, "GSUB") == 0
+ && otf->gsub->FeatureList.FeatureCount > 0)
XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
- if (OTF_get_table (otf, "GPOS") == 0)
+ if (OTF_get_table (otf, "GPOS") == 0
+ && otf->gpos->FeatureList.FeatureCount > 0)
XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
return gsub_gpos;
}
}
else if (anchor->AnchorFormat == 3)
{
- if (anchor->f.f2.XDeviceTable.offset)
+ if (anchor->f.f2.XDeviceTable.offset
+ && anchor->f.f2.XDeviceTable.DeltaValue)
*x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
- if (anchor->f.f2.YDeviceTable.offset)
+ if (anchor->f.f2.YDeviceTable.offset
+ && anchor->f.f2.YDeviceTable.DeltaValue)
*y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
}
}
static OTF_GlyphString otf_gstring;
+static void
+setup_otf_gstring (int size)
+{
+ if (otf_gstring.size == 0)
+ {
+ otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * size);
+ otf_gstring.size = size;
+ }
+ else if (otf_gstring.size < size)
+ {
+ otf_gstring.glyphs = (OTF_Glyph *) realloc (otf_gstring.glyphs,
+ sizeof (OTF_Glyph) * size);
+ otf_gstring.size = size;
+ }
+ otf_gstring.used = size;
+ memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
+}
+
+
static int
ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
MFLTFont *font;
}
}
- if (otf_gstring.size == 0)
- {
- otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
- otf_gstring.size = len;
- }
- else if (otf_gstring.size < len)
- {
- otf_gstring.glyphs = (OTF_Glyph *) realloc (otf_gstring.glyphs,
- sizeof (OTF_Glyph) * len);
- otf_gstring.size = len;
- }
- otf_gstring.used = len;
- memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
+ setup_otf_gstring (len);
for (i = 0; i < len; i++)
{
otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
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;;
+ mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
if (otfg->f.f4.base_anchor->AnchorFormat != 1)
adjust_anchor (ft_face, otfg->f.f4.base_anchor,
extern Lisp_Object QCfamily;
-Lisp_Object
+static Lisp_Object
ftfont_shape_by_flt (lgstring, font, ft_face, otf)
Lisp_Object lgstring;
struct font *font;
FT_Face ft_face;
OTF *otf;
{
- EMACS_UINT len = LGSTRING_LENGTH (lgstring);
+ EMACS_UINT len = LGSTRING_GLYPH_LEN (lgstring);
EMACS_UINT i;
struct MFLTFontFT flt_font_ft;
+ MFLT *flt = NULL;
+ int with_variation_selector = 0;
if (! m17n_flt_initialized)
{
}
for (i = 0; i < len; i++)
- if (NILP (LGSTRING_GLYPH (lgstring, i)))
- break;
+ {
+ Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
+ int c;
+
+ if (NILP (g))
+ break;
+ c = LGLYPH_CHAR (g);
+ if (CHAR_VARIATION_SELECTOR_P (c))
+ with_variation_selector++;
+ }
len = i;
+ if (with_variation_selector)
+ {
+ setup_otf_gstring (len);
+ for (i = 0; i < len; i++)
+ {
+ Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
+
+ otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
+ otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
+ otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
+ }
+ OTF_drive_cmap (otf, &otf_gstring);
+ for (i = 0; i < otf_gstring.used; i++)
+ {
+ OTF_Glyph *otfg = otf_gstring.glyphs + i;
+ Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
+ Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
+
+ LGLYPH_SET_CODE (g0, otfg->glyph_id);
+ LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
+ LGSTRING_SET_GLYPH (lgstring, i, g0);
+ }
+ if (len > otf_gstring.used)
+ {
+ len = otf_gstring.used;
+ LGSTRING_SET_GLYPH (lgstring, len, Qnil);
+ }
+ }
if (gstring.allocated == 0)
{
gstring.glyphs = realloc (gstring.glyphs,
sizeof (MFLTGlyph) * gstring.allocated);
}
+ memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
for (i = 0; i < len; i++)
- gstring.glyphs[i].c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
+ {
+ Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
+
+ gstring.glyphs[i].c = LGLYPH_CHAR (g);
+ if (with_variation_selector)
+ {
+ gstring.glyphs[i].code = LGLYPH_CODE (g);
+ gstring.glyphs[i].encoded = 1;
+ }
+ }
+
gstring.used = len;
gstring.r2l = 0;
flt_font_ft.flt_font.family = Mnil;
else
flt_font_ft.flt_font.family
- = msymbol ((char *) SDATA (SYMBOL_NAME (family)));
+ = msymbol ((char *) SDATA (Fdowncase (SYMBOL_NAME (family))));
}
flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
flt_font_ft.font = font;
flt_font_ft.ft_face = ft_face;
flt_font_ft.otf = otf;
+ if (len > 1
+ && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
+ /* A little bit ad hoc. Perhaps, shaper must get script and
+ language information, and select a proper flt for them
+ here. */
+ flt = mflt_get (msymbol ("combining"));
for (i = 0; i < 3; i++)
{
- int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, NULL);
+ int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
if (result != -2)
break;
gstring.allocated += gstring.allocated;
gstring.glyphs = realloc (gstring.glyphs,
sizeof (MFLTGlyph) * gstring.allocated);
}
- if (gstring.used > LGSTRING_LENGTH (lgstring))
+ if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
return Qnil;
for (i = 0; i < gstring.used; i++)
{
return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf);
}
+#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
+
+static int
+ftfont_variation_glyphs (font, c, variations)
+ struct font *font;
+ int c;
+ unsigned variations[256];
+{
+ struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ OTF *otf = ftfont_get_otf (ftfont_info);
+
+ if (! otf)
+ return 0;
+ return OTF_get_variation_glyphs (otf, c, variations);
+}
+
+#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
#endif /* HAVE_M17N_FLT */
#endif /* HAVE_LIBOTF */