1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-05 11:45:45 +00:00

(struct otf_list): Delete it.

(otf_list): Make it a lisp variable..
(otf_open): Use lispy otf_list.
(generate_otf_features): Renamed from parse_gsub_gpos_spec.
(check_otf_features): New function.
(font_otf_DeviceTable, font_otf_ValueRecord, font_otf_Anchor): New
functinos.
(font_drive_otf): New function merging font_otf_gsub and
font_otf_gpos.
(font_open_for_lface): New arg spec.  Change argument order.
(font_load_for_face): Adjusted for the change of
font_open_for_lface.
(Ffont_drive_otf): New function merging Ffont_otf_gsub and
Ffont_otf_gpos.
(syms_of_font): Staticpro otf_list.  Delete defsubr of
Sfont_otf_gsub and Sfont_otf_gpos.  Defsubr Sfont_drive_otf.
This commit is contained in:
Kenichi Handa 2007-04-25 12:05:28 +00:00
parent c927d1df98
commit 733fd013f6

View File

@ -1483,14 +1483,7 @@ check_gstring (gstring)
#ifdef HAVE_LIBOTF
#include <otf.h>
struct otf_list
{
Lisp_Object entity;
OTF *otf;
struct otf_list *next;
};
static struct otf_list *otf_list;
Lisp_Object otf_list;
static Lisp_Object
otf_tag_symbol (tag)
@ -1507,19 +1500,18 @@ otf_open (entity, file)
Lisp_Object entity;
char *file;
{
struct otf_list *list = otf_list;
while (list && ! EQ (list->entity, entity))
list = list->next;
if (! list)
Lisp_Object val = Fassoc (entity, otf_list);
OTF *otf;
if (! NILP (val))
otf = XSAVE_VALUE (XCDR (val))->pointer;
else
{
list = malloc (sizeof (struct otf_list));
list->entity = entity;
list->otf = file ? OTF_open (file) : NULL;
list->next = otf_list;
otf_list = list;
otf = file ? OTF_open (file) : NULL;
val = make_save_value (otf, 0);
otf_list = Fcons (Fcons (entity, val), otf_list);
}
return list->otf;
return otf;
}
@ -1597,58 +1589,41 @@ font_otf_capability (font)
return capability;
}
/* Parse OTF features in SPEC and write a proper features spec string
in FEATURES for the call of OTF_drive_gsub/gpos (of libotf). It is
assured that the sufficient memory has already allocated for
FEATURES. */
static void
parse_gsub_gpos_spec (spec, script, langsys, features, nbytes)
generate_otf_features (spec, features)
Lisp_Object spec;
char **script, **langsys, *features;
int nbytes;
char *features;
{
Lisp_Object val;
char *p, *pend;
int asterisk;
CHECK_CONS (spec);
val = XCAR (spec);
CHECK_SYMBOL (val);
*script = (char *) SDATA (SYMBOL_NAME (val));
spec = XCDR (spec);
CHECK_CONS (spec);
val = XCAR (spec);
CHECK_SYMBOL (val);
*langsys = NILP (val) ? NULL : (char *) SDATA (SYMBOL_NAME (val));
spec = XCDR (spec);
p = features, pend = p + nbytes - 1;
p = features;
*p = '\0';
for (asterisk = 0; CONSP (spec); spec = XCDR (spec))
{
val = XCAR (spec);
CHECK_SYMBOL (val);
if (p > features)
{
if (p >= pend)
break;
*p++ = ',';
}
*p++ = ',';
if (SREF (SYMBOL_NAME (val), 0) == '*')
{
asterisk = 1;
if (p >= pend)
break;
*p++ = '*';
}
else if (! asterisk)
{
val = SYMBOL_NAME (val);
if (p + SBYTES (val) >= pend)
break;
p += sprintf (p, "%s", SDATA (val));
}
else
{
val = SYMBOL_NAME (val);
if (p + 1 + SBYTES (val)>= pend)
break;
p += sprintf (p, "~%s", SDATA (val));
}
}
@ -1682,30 +1657,131 @@ adjust_anchor (struct font *font, OTF_Anchor *anchor,
}
}
static void
check_otf_features (otf_features)
Lisp_Object otf_features;
{
Lisp_Object val, elt;
CHECK_CONS (otf_features);
CHECK_SYMBOL (XCAR (otf_features));
otf_features = XCDR (otf_features);
CHECK_CONS (otf_features);
CHECK_SYMBOL (XCAR (otf_features));
otf_features = XCDR (otf_features);
for (val = Fcar (otf_features); ! NILP (val); val = Fcdr (val))
{
CHECK_SYMBOL (Fcar (val));
if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
error ("Invalid OTF GSUB feature: %s", SYMBOL_NAME (XCAR (val)));
}
otf_features = XCDR (otf_features);
for (val = Fcar (otf_features); ! NILP (val); val = Fcdr (val))
{
CHECK_SYMBOL (Fcar (val));
if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
error ("Invalid OTF GPOS feature: %s", SYMBOL_NAME (XCAR (val)));
}
}
Lisp_Object
font_otf_DeviceTable (device_table)
OTF_DeviceTable *device_table;
{
int len = device_table->StartSize - device_table->EndSize + 1;
return Fcons (make_number (len),
make_unibyte_string (device_table->DeltaValue, len));
}
Lisp_Object
font_otf_ValueRecord (value_format, value_record)
int value_format;
OTF_ValueRecord *value_record;
{
Lisp_Object val = Fmake_vector (make_number (8), Qnil);
if (value_format & OTF_XPlacement)
ASET (val, 0, value_record->XPlacement);
if (value_format & OTF_YPlacement)
ASET (val, 1, value_record->YPlacement);
if (value_format & OTF_XAdvance)
ASET (val, 2, value_record->XAdvance);
if (value_format & OTF_YAdvance)
ASET (val, 3, value_record->YAdvance);
if (value_format & OTF_XPlaDevice)
ASET (val, 4, font_otf_DeviceTable (&value_record->XPlaDevice));
if (value_format & OTF_YPlaDevice)
ASET (val, 4, font_otf_DeviceTable (&value_record->YPlaDevice));
if (value_format & OTF_XAdvDevice)
ASET (val, 4, font_otf_DeviceTable (&value_record->XAdvDevice));
if (value_format & OTF_YAdvDevice)
ASET (val, 4, font_otf_DeviceTable (&value_record->YAdvDevice));
return val;
}
Lisp_Object
font_otf_Anchor (anchor)
OTF_Anchor *anchor;
{
Lisp_Object val;
val = Fmake_vector (make_number (anchor->AnchorFormat + 1), Qnil);
ASET (val, 0, make_number (anchor->XCoordinate));
ASET (val, 1, make_number (anchor->YCoordinate));
if (anchor->AnchorFormat == 2)
ASET (val, 2, make_number (anchor->f.f1.AnchorPoint));
else
{
ASET (val, 3, font_otf_DeviceTable (&anchor->f.f2.XDeviceTable));
ASET (val, 4, font_otf_DeviceTable (&anchor->f.f2.YDeviceTable));
}
return val;
}
#define REPLACEMENT_CHARACTER 0xFFFD
/* Drive FONT's OTF GSUB features according to GSUB_SPEC. See the
comment of (sturct font_driver).otf_gsub. */
/* Drive FONT's OpenType FEATURES. See the comment of (sturct
font_driver).drive_otf. */
int
font_otf_gsub (font, gsub_spec, gstring_in, from, to, gstring_out, idx,
font_drive_otf (font, otf_features, gstring_in, from, to, gstring_out, idx,
alternate_subst)
struct font *font;
Lisp_Object gsub_spec;
Lisp_Object otf_features;
Lisp_Object gstring_in;
int from, to;
Lisp_Object gstring_out;
int idx, alternate_subst;
{
Lisp_Object val;
int len;
int i;
OTF *otf;
OTF_GlyphString otf_gstring;
OTF_Glyph *g;
char *script, *langsys, features[256];
char *script, *langsys = NULL, *gsub_features = NULL, *gpos_features = NULL;
int need_cmap;
parse_gsub_gpos_spec (gsub_spec, &script, &langsys, features, 256);
val = XCAR (otf_features);
script = SDATA (SYMBOL_NAME (val));
otf_features = XCDR (otf_features);
val = XCAR (otf_features);
langsys = NILP (val) ? NULL : SDATA (SYMBOL_NAME (val));
otf_features = XCDR (otf_features);
val = XCAR (otf_features);
if (! NILP (val))
{
gsub_features = alloca (XINT (Flength (val)) * 6);
generate_otf_features (val, &script, &langsys, gsub_features);
}
otf_features = XCDR (otf_features);
val = XCAR (otf_features);
if (! NILP (val))
{
gpos_features = alloca (XINT (Flength (val)) * 6);
generate_otf_features (val, &script, &langsys, gpos_features);
}
otf = otf_open (font->entity, font->file_name);
if (! otf)
@ -1714,8 +1790,10 @@ font_otf_gsub (font, gsub_spec, gstring_in, from, to, gstring_out, idx,
return 0;
if (OTF_get_table (otf, "cmap") < 0)
return 0;
if (OTF_check_table (otf, "GSUB") < 0)
return 0;
if ((! gsub_features || OTF_check_table (otf, "GSUB") < 0)
&& (! gpos_features || OTF_check_table (otf, "GPOS") < 0))
return 0;
len = to - from;
otf_gstring.size = otf_gstring.used = len;
otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
@ -1735,216 +1813,164 @@ font_otf_gsub (font, gsub_spec, gstring_in, from, to, gstring_out, idx,
else
otf_gstring.glyphs[i].glyph_id = XINT (LGLYPH_CODE (g));
}
if (need_cmap)
OTF_drive_cmap (otf, &otf_gstring);
OTF_drive_gdef (otf, &otf_gstring);
if ((alternate_subst
? OTF_drive_gsub_alternate (otf, &otf_gstring, script, langsys, features)
: OTF_drive_gsub (otf, &otf_gstring, script, langsys, features)) < 0)
{
free (otf_gstring.glyphs);
return 0;
}
if (ASIZE (gstring_out) < idx + otf_gstring.used)
{
free (otf_gstring.glyphs);
return -1;
}
for (i = 0, g = otf_gstring.glyphs; i < otf_gstring.used;)
if (gsub_features)
{
int i0 = g->f.index.from, i1 = g->f.index.to;
Lisp_Object glyph = LGSTRING_GLYPH (gstring_in, from + i0);
Lisp_Object min_idx = AREF (glyph, 0);
Lisp_Object max_idx = AREF (glyph, 1);
if (i0 < i1)
if ((alternate_subst
? OTF_drive_gsub_alternate (otf, &otf_gstring, script, langsys,
gsub_features)
: OTF_drive_gsub (otf, &otf_gstring, script, langsys,
gsub_features)) < 0)
{
int min_idx_i = XINT (min_idx), max_idx_i = XINT (max_idx);
free (otf_gstring.glyphs);
return 0;
}
if (ASIZE (gstring_out) < idx + otf_gstring.used)
{
free (otf_gstring.glyphs);
return -1;
}
for (i = 0, g = otf_gstring.glyphs; i < otf_gstring.used;)
{
int i0 = g->f.index.from, i1 = g->f.index.to;
Lisp_Object glyph = LGSTRING_GLYPH (gstring_in, from + i0);
Lisp_Object min_idx = AREF (glyph, 0);
Lisp_Object max_idx = AREF (glyph, 1);
for (i0++; i0 <= i1; i0++)
if (i0 < i1)
{
glyph = LGSTRING_GLYPH (gstring_in, from + i0);
if (min_idx_i > XINT (AREF (glyph, 0)))
min_idx_i = XINT (AREF (glyph, 0));
if (max_idx_i < XINT (AREF (glyph, 1)))
max_idx_i = XINT (AREF (glyph, 1));
int min_idx_i = XINT (min_idx), max_idx_i = XINT (max_idx);
for (i0++; i0 <= i1; i0++)
{
glyph = LGSTRING_GLYPH (gstring_in, from + i0);
if (min_idx_i > XINT (AREF (glyph, 0)))
min_idx_i = XINT (AREF (glyph, 0));
if (max_idx_i < XINT (AREF (glyph, 1)))
max_idx_i = XINT (AREF (glyph, 1));
}
min_idx = make_number (min_idx_i);
max_idx = make_number (max_idx_i);
i0 = g->f.index.from;
}
for (; i < otf_gstring.used && g->f.index.from == i0; i++, g++)
{
glyph = LGSTRING_GLYPH (gstring_out, idx + i);
ASET (glyph, 0, min_idx);
ASET (glyph, 1, max_idx);
if (g->c > 0)
LGLYPH_SET_CHAR (glyph, make_number (g->c));
else
LGLYPH_SET_CHAR (glyph, make_number (REPLACEMENT_CHARACTER));
LGLYPH_SET_CODE (glyph, make_number (g->glyph_id));
}
min_idx = make_number (min_idx_i);
max_idx = make_number (max_idx_i);
i0 = g->f.index.from;
}
for (; i < otf_gstring.used && g->f.index.from == i0; i++, g++)
{
glyph = LGSTRING_GLYPH (gstring_out, idx + i);
ASET (glyph, 0, min_idx);
ASET (glyph, 1, max_idx);
if (g->c > 0)
LGLYPH_SET_CHAR (glyph, make_number (g->c));
else
LGLYPH_SET_CHAR (glyph, make_number (REPLACEMENT_CHARACTER));
LGLYPH_SET_CODE (glyph, make_number (g->glyph_id));
}
}
free (otf_gstring.glyphs);
return i;
}
/* Drive FONT's OTF GPOS features according to GPOS_SPEC. See the
comment of (sturct font_driver).otf_gpos. */
int
font_otf_gpos (font, gpos_spec, gstring, from, to)
struct font *font;
Lisp_Object gpos_spec;
Lisp_Object gstring;
int from, to;
{
int len;
int i;
OTF *otf;
OTF_GlyphString otf_gstring;
OTF_Glyph *g;
char *script, *langsys, features[256];
int need_cmap;
Lisp_Object glyph;
int u, size;
Lisp_Object base, mark;
parse_gsub_gpos_spec (gpos_spec, &script, &langsys, features, 256);
otf = otf_open (font->entity, font->file_name);
if (! otf)
return 0;
if (OTF_get_table (otf, "head") < 0)
return 0;
if (OTF_get_table (otf, "cmap") < 0)
return 0;
if (OTF_check_table (otf, "GPOS") < 0)
return 0;
len = to - from;
otf_gstring.size = otf_gstring.used = len;
otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
for (i = 0, need_cmap = 0; i < len; i++)
if (gpos_features)
{
glyph = LGSTRING_GLYPH (gstring, from + i);
otf_gstring.glyphs[i].c = XINT (LGLYPH_CHAR (glyph));
if (otf_gstring.glyphs[i].c == REPLACEMENT_CHARACTER)
otf_gstring.glyphs[i].c = 0;
if (NILP (LGLYPH_CODE (glyph)))
Lisp_Object glyph;
int u = otf->head->unitsPerEm;
int size = font->pixel_size;
Lisp_Object base = Qnil, mark = Qnil;
if (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
gpos_features) < 0)
{
otf_gstring.glyphs[i].glyph_id = 0;
need_cmap = 1;
free (otf_gstring.glyphs);
return 0;
}
else
otf_gstring.glyphs[i].glyph_id = XINT (LGLYPH_CODE (glyph));
}
if (need_cmap)
OTF_drive_cmap (otf, &otf_gstring);
OTF_drive_gdef (otf, &otf_gstring);
if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, features) < 0)
{
free (otf_gstring.glyphs);
return 0;
}
u = otf->head->unitsPerEm;
size = font->pixel_size;
base = mark = Qnil;
for (i = 0, g = otf_gstring.glyphs; i < otf_gstring.used; i++, g++)
{
Lisp_Object prev;
int xoff = 0, yoff = 0, width_adjust = 0;
if (! g->glyph_id)
continue;
glyph = LGSTRING_GLYPH (gstring, from + i);
switch (g->positioning_type)
for (i = 0, g = otf_gstring.glyphs; i < otf_gstring.used; i++, g++)
{
case 0:
break;
case 1: case 2:
{
int format = g->f.f1.format;
Lisp_Object prev;
int xoff = 0, yoff = 0, width_adjust = 0;
if (format & OTF_XPlacement)
xoff = g->f.f1.value->XPlacement * size / u;
if (format & OTF_XPlaDevice)
xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, size);
if (format & OTF_YPlacement)
yoff = - (g->f.f1.value->YPlacement * size / u);
if (format & OTF_YPlaDevice)
yoff -= DEVICE_DELTA (g->f.f1.value->YPlaDevice, size);
if (format & OTF_XAdvance)
width_adjust += g->f.f1.value->XAdvance * size / u;
if (format & OTF_XAdvDevice)
width_adjust += DEVICE_DELTA (g->f.f1.value->XAdvDevice, size);
}
break;
case 3:
/* Not yet supported. */
break;
case 4: case 5:
if (NILP (base))
break;
prev = base;
goto label_adjust_anchor;
default: /* i.e. case 6 */
if (NILP (mark))
break;
prev = mark;
if (! g->glyph_id)
continue;
label_adjust_anchor:
{
int base_x, base_y, mark_x, mark_y, width;
unsigned code;
base_x = g->f.f4.base_anchor->XCoordinate * size / u;
base_y = g->f.f4.base_anchor->YCoordinate * size / u;
mark_x = g->f.f4.mark_anchor->XCoordinate * size / u;
mark_y = g->f.f4.mark_anchor->YCoordinate * size / u;
code = XINT (LGLYPH_CODE (prev));
if (g->f.f4.base_anchor->AnchorFormat != 1)
adjust_anchor (font, g->f.f4.base_anchor,
code, size, &base_x, &base_y);
if (g->f.f4.mark_anchor->AnchorFormat != 1)
adjust_anchor (font, g->f.f4.mark_anchor,
code, size, &mark_x, &mark_y);
if (NILP (LGLYPH_WIDTH (prev)))
switch (g->positioning_type)
{
case 0:
break;
case 1: case 2:
{
width = font->driver->text_extents (font, &code, 1, NULL);
LGLYPH_SET_WIDTH (prev, make_number (width));
int format = g->f.f1.format;
if (format & OTF_XPlacement)
xoff = g->f.f1.value->XPlacement * size / u;
if (format & OTF_XPlaDevice)
xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, size);
if (format & OTF_YPlacement)
yoff = - (g->f.f1.value->YPlacement * size / u);
if (format & OTF_YPlaDevice)
yoff -= DEVICE_DELTA (g->f.f1.value->YPlaDevice, size);
if (format & OTF_XAdvance)
width_adjust += g->f.f1.value->XAdvance * size / u;
if (format & OTF_XAdvDevice)
width_adjust += DEVICE_DELTA (g->f.f1.value->XAdvDevice, size);
}
else
width = XINT (LGLYPH_WIDTH (prev));
xoff = XINT (LGLYPH_XOFF (prev)) + (base_x - width) - mark_x;
yoff = XINT (LGLYPH_YOFF (prev)) + mark_y - base_y;
}
break;
case 3:
/* Not yet supported. */
break;
case 4: case 5:
if (NILP (base))
break;
prev = base;
goto label_adjust_anchor;
default: /* i.e. case 6 */
if (NILP (mark))
break;
prev = mark;
label_adjust_anchor:
{
int base_x, base_y, mark_x, mark_y, width;
unsigned code;
base_x = g->f.f4.base_anchor->XCoordinate * size / u;
base_y = g->f.f4.base_anchor->YCoordinate * size / u;
mark_x = g->f.f4.mark_anchor->XCoordinate * size / u;
mark_y = g->f.f4.mark_anchor->YCoordinate * size / u;
code = XINT (LGLYPH_CODE (prev));
if (g->f.f4.base_anchor->AnchorFormat != 1)
adjust_anchor (font, g->f.f4.base_anchor,
code, size, &base_x, &base_y);
if (g->f.f4.mark_anchor->AnchorFormat != 1)
adjust_anchor (font, g->f.f4.mark_anchor,
code, size, &mark_x, &mark_y);
if (NILP (LGLYPH_WIDTH (prev)))
{
width = font->driver->text_extents (font, &code, 1, NULL);
LGLYPH_SET_WIDTH (prev, make_number (width));
}
else
width = XINT (LGLYPH_WIDTH (prev));
xoff = XINT (LGLYPH_XOFF (prev)) + (base_x - width) - mark_x;
yoff = XINT (LGLYPH_YOFF (prev)) + mark_y - base_y;
}
}
if (xoff || yoff || width_adjust)
{
Lisp_Object adjustment = Fmake_vector (make_number (3), Qnil);
ASET (adjustment, 0, make_number (xoff));
ASET (adjustment, 1, make_number (yoff));
ASET (adjustment, 2, make_number (width_adjust));
LGLYPH_SET_ADJUSTMENT (glyph, adjustment);
}
if (g->GlyphClass == OTF_GlyphClass0)
base = mark = glyph;
else if (g->GlyphClass == OTF_GlyphClassMark)
mark = glyph;
else
base = glyph;
}
if (xoff || yoff || width_adjust)
{
Lisp_Object adjustment = Fmake_vector (make_number (3), Qnil);
ASET (adjustment, 0, make_number (xoff));
ASET (adjustment, 1, make_number (yoff));
ASET (adjustment, 2, make_number (width_adjust));
LGLYPH_SET_ADJUSTMENT (glyph, adjustment);
}
if (g->GlyphClass == OTF_GlyphClass0)
base = mark = glyph;
else if (g->GlyphClass == OTF_GlyphClassMark)
mark = glyph;
else
base = glyph;
}
free (otf_gstring.glyphs);
@ -2660,16 +2686,23 @@ font_find_for_lface (f, lface, spec)
}
Lisp_Object
font_open_for_lface (f, lface, entity)
font_open_for_lface (f, entity, lface, spec)
FRAME_PTR f;
Lisp_Object *lface;
Lisp_Object entity;
Lisp_Object *lface;
Lisp_Object spec;
{
double pt = XINT (lface[LFACE_HEIGHT_INDEX]);
int size;
pt /= 10;
size = POINT_TO_PIXEL (pt, f->resy);
if (FONT_SPEC_P (spec) && INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
size = XINT (AREF (spec, FONT_SIZE_INDEX));
else
{
double pt = XINT (lface[LFACE_HEIGHT_INDEX]);
pt /= 10;
size = POINT_TO_PIXEL (pt, f->resy);
}
return font_open_entity (f, entity, size);
}
@ -2685,7 +2718,7 @@ font_load_for_face (f, face)
Lisp_Object entity = font_find_for_lface (f, face->lface, Qnil);
if (! NILP (entity))
font_object = font_open_for_lface (f, face->lface, entity);
font_object = font_open_for_lface (f, entity, face->lface, Qnil);
}
if (! NILP (font_object))
@ -3237,7 +3270,7 @@ and is a vector of this form:
HEADER is a vector of this form:
[FONT-OBJECT LBEARING RBEARING WIDTH ASCENT DESCENT]
where
FONT-OBJECT is a font-object for all glyphs in the G-string,
FONT-OBJECT is a font-object for all glyphs in the g-string,
LBEARING thry DESCENT is the metrics (in pixels) of the whole G-string.
GLYPH is a vector of this form:
[ FROM-IDX TO-IDX C CODE WIDTH [ [X-OFF Y-OFF WADJUST] | nil] ]
@ -3349,26 +3382,25 @@ FONT-OBJECT may be nil if GSTRING already already contains one. */)
return Qnil;
}
DEFUN ("font-otf-gsub", Ffont_otf_gsub, Sfont_otf_gsub, 6, 6, 0,
doc: /* Apply OpenType "GSUB" features on glyph-string GSTRING-IN.
FEATURE-SPEC specifies which featuress to apply in this format:
(SCRIPT LANGSYS FEATURE ...)
DEFUN ("font-drive-otf", Ffont_drive_otf, Sfont_drive_otf, 6, 6, 0,
doc: /* Apply OpenType features on glyph-string GSTRING-IN.
OTF-SPEC specifies which featuress to apply in this format:
(SCRIPT LANGSYS GSUB GPOS)
where
SCRIPT is a symbol specifying a script tag of OpenType,
LANGSYS is a symbol specifying a langsys tag of OpenType,
FEATURE is a symbol specifying a feature tag of Opentype.
GSUB and GPOS, if non-nil, are lists of symbols specifying feature tags.
If LANGYS is nil, the default langsys is selected.
The features are applied in the order appeared in the list. FEATURE
may be a symbol `*', in which case all available features not appeared
in this list are applied, and the remaining FEATUREs are not ignored.
For instance, (mlym nil vatu pstf * haln) means to apply vatu and pstf
in this order, then to apply all available features other than vatu,
pstf, and haln.
The features are applied in the order appeared in the list. The
symbol `*' means to apply all available features not appeared in this
list, and the remaining features are ignored. For instance, (vatu
pstf * haln) is to apply vatu and pstf in this order, then to apply
all available features other than vatu, pstf, and haln.
The features are applied to the glyphs in the range FROM and TO of
GSTRING-IN.
the glyph-string GSTRING-IN.
If some of a feature is actually applicable, the resulting glyphs are
produced in the glyph-string GSTRING-OUT from the index INDEX. In
@ -3382,18 +3414,26 @@ produced in GSTRING-OUT, and the value is nil.
See the documentation of `font-make-gstring' for the format of
glyph-string. */)
(feature_spec, gstring_in, from, to, gstring_out, index)
Lisp_Object feature_spec, gstring_in, from, to, gstring_out, index;
(otf_features, gstring_in, from, to, gstring_out, index)
Lisp_Object otf_features, gstring_in, from, to, gstring_out, index;
{
Lisp_Object font_object = LGSTRING_FONT (gstring_in);
struct font *font = XSAVE_VALUE (font_object)->pointer;
Lisp_Object val;
struct font *font;
int len, num;
check_otf_features (otf_features);
CHECK_FONT_GET_OBJECT (font_object, font);
if (! font->driver->otf_gsub)
if (! font->driver->otf_drive)
error ("Font backend %s can't drive OpenType GSUB table",
SDATA (SYMBOL_NAME (font->driver->type)));
CHECK_CONS (feature_spec);
CHECK_CONS (otf_features);
CHECK_SYMBOL (XCAR (otf_features));
val = XCDR (otf_features);
CHECK_SYMBOL (XCAR (val));
val = XCDR (otf_features);
if (! NILP (val))
CHECK_CONS (val);
len = check_gstring (gstring_in);
CHECK_VECTOR (gstring_out);
CHECK_NATNUM (from);
@ -3404,47 +3444,14 @@ glyph-string. */)
args_out_of_range_3 (from, to, make_number (len));
if (XINT (index) >= ASIZE (gstring_out))
args_out_of_range (index, make_number (ASIZE (gstring_out)));
num = font->driver->otf_gsub (font, feature_spec,
gstring_in, XINT (from), XINT (to),
gstring_out, XINT (index), 0);
num = font->driver->otf_drive (font, otf_features,
gstring_in, XINT (from), XINT (to),
gstring_out, XINT (index), 0);
if (num < 0)
return Qnil;
return make_number (num);
}
DEFUN ("font-otf-gpos", Ffont_otf_gpos, Sfont_otf_gpos, 4, 4, 0,
doc: /* Apply OpenType "GPOS" features on glyph-string GSTRING.
FEATURE-SPEC specifies which features to apply in this format:
(SCRIPT LANGSYS FEATURE ...)
See the documentation of `font-otf-gsub' for more detail.
The features are applied to the glyphs in the range FROM and TO of
GSTRING. */)
(gpos_spec, gstring, from, to)
Lisp_Object gpos_spec, gstring, from, to;
{
Lisp_Object font_object = LGSTRING_FONT (gstring);
struct font *font;
int len, num;
CHECK_FONT_GET_OBJECT (font_object, font);
if (! font->driver->otf_gpos)
error ("Font backend %s can't drive OpenType GPOS table",
SDATA (SYMBOL_NAME (font->driver->type)));
CHECK_CONS (gpos_spec);
len = check_gstring (gstring);
CHECK_NATNUM (from);
CHECK_NATNUM (to);
if (XINT (from) >= XINT (to) || XINT (to) > len)
args_out_of_range_3 (from, to, make_number (len));
num = font->driver->otf_gpos (font, gpos_spec,
gstring, XINT (from), XINT (to));
return (num <= 0 ? Qnil : Qt);
}
DEFUN ("font-otf-alternates", Ffont_otf_alternates, Sfont_otf_alternates,
3, 3, 0,
doc: /* Return a list of alternate glyphs of CHARACTER in FONT-OBJECT.
@ -3457,8 +3464,8 @@ The value is a list of cons cells of the format (GLYPH-ID . CHARACTER),
where GLYPH-ID is a glyph index of the font, and CHARACTER is a
character code corresponding to the glyph or nil if there's no
corresponding character. */)
(font_object, character, feature_spec)
Lisp_Object font_object, character, feature_spec;
(font_object, character, otf_features)
Lisp_Object font_object, character, otf_features;
{
struct font *font;
Lisp_Object gstring_in, gstring_out, g;
@ -3466,18 +3473,18 @@ corresponding character. */)
int i, num;
CHECK_FONT_GET_OBJECT (font_object, font);
if (! font->driver->otf_gsub)
if (! font->driver->otf_drive)
error ("Font backend %s can't drive OpenType GSUB table",
SDATA (SYMBOL_NAME (font->driver->type)));
CHECK_CHARACTER (character);
CHECK_CONS (feature_spec);
CHECK_CONS (otf_features);
gstring_in = Ffont_make_gstring (font_object, make_number (1));
g = LGSTRING_GLYPH (gstring_in, 0);
LGLYPH_SET_CHAR (g, character);
gstring_out = Ffont_make_gstring (font_object, make_number (10));
while ((num = font->driver->otf_gsub (font, feature_spec, gstring_in, 0, 1,
gstring_out, 0, 1)) < 0)
while ((num = font->driver->otf_drive (font, otf_features, gstring_in, 0, 1,
gstring_out, 0, 1)) < 0)
gstring_out = Ffont_make_gstring (font_object,
make_number (ASIZE (gstring_out) * 2));
alternates = Qnil;
@ -3792,6 +3799,11 @@ syms_of_font ()
staticpro (&scratch_font_prefer);
scratch_font_prefer = Ffont_spec (0, NULL);
#ifdef HAVE_LIBOTF
staticpro (&otf_list);
otf_list = Qnil;
#endif
defsubr (&Sfontp);
defsubr (&Sfont_spec);
defsubr (&Sfont_get);
@ -3804,8 +3816,7 @@ syms_of_font ()
defsubr (&Sinternal_set_font_style_table);
defsubr (&Sfont_make_gstring);
defsubr (&Sfont_fill_gstring);
defsubr (&Sfont_otf_gsub);
defsubr (&Sfont_otf_gpos);
defsubr (&Sfont_drive_otf);
defsubr (&Sfont_otf_alternates);
#ifdef FONT_DEBUG