diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/font/luafont.w')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/font/luafont.w | 2400 |
1 files changed, 2400 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/font/luafont.w b/Build/source/texk/web2c/luatexdir/font/luafont.w new file mode 100644 index 00000000000..bde66530fb4 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/luafont.w @@ -0,0 +1,2400 @@ +% luafont.w +% +% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org> +% +% This file is part of LuaTeX. +% +% LuaTeX is free software; you can redistribute it and/or modify it under +% the terms of the GNU General Public License as published by the Free +% Software Foundation; either version 2 of the License, or (at your +% option) any later version. +% +% LuaTeX is distributed in the hope that it will be useful, but WITHOUT +% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +% License for more details. +% +% You should have received a copy of the GNU General Public License along +% with LuaTeX; if not, see <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: luafont.w 3584 2010-04-02 17:45:55Z hhenkel $ " +"$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/font/luafont.w $"; + +#include "ptexlib.h" +#include "lua/luatex-api.h" + +#define noVERBOSE + +const char *font_type_strings[] = { "unknown", "virtual", "real", NULL }; +const char *font_format_strings[] = + { "unknown", "type1", "type3", "truetype", "opentype", NULL }; +const char *font_embedding_strings[] = + { "unknown", "no", "subset", "full", NULL }; + +const char *ligature_type_strings[] = + { "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", + "|=:|>>", NULL +}; + +const char *MATH_param_names[] = { + "nil", + "ScriptPercentScaleDown", + "ScriptScriptPercentScaleDown", + "DelimitedSubFormulaMinHeight", + "DisplayOperatorMinHeight", + "MathLeading", + "AxisHeight", + "AccentBaseHeight", + "FlattenedAccentBaseHeight", + "SubscriptShiftDown", + "SubscriptTopMax", + "SubscriptBaselineDropMin", + "SuperscriptShiftUp", + "SuperscriptShiftUpCramped", + "SuperscriptBottomMin", + "SuperscriptBaselineDropMax", + "SubSuperscriptGapMin", + "SuperscriptBottomMaxWithSubscript", + "SpaceAfterScript", + "UpperLimitGapMin", + "UpperLimitBaselineRiseMin", + "LowerLimitGapMin", + "LowerLimitBaselineDropMin", + "StackTopShiftUp", + "StackTopDisplayStyleShiftUp", + "StackBottomShiftDown", + "StackBottomDisplayStyleShiftDown", + "StackGapMin", + "StackDisplayStyleGapMin", + "StretchStackTopShiftUp", + "StretchStackBottomShiftDown", + "StretchStackGapAboveMin", + "StretchStackGapBelowMin", + "FractionNumeratorShiftUp", + "FractionNumeratorDisplayStyleShiftUp", + "FractionDenominatorShiftDown", + "FractionDenominatorDisplayStyleShiftDown", + "FractionNumeratorGapMin", + "FractionNumeratorDisplayStyleGapMin", + "FractionRuleThickness", + "FractionDenominatorGapMin", + "FractionDenominatorDisplayStyleGapMin", + "SkewedFractionHorizontalGap", + "SkewedFractionVerticalGap", + "OverbarVerticalGap", + "OverbarRuleThickness", + "OverbarExtraAscender", + "UnderbarVerticalGap", + "UnderbarRuleThickness", + "UnderbarExtraDescender", + "RadicalVerticalGap", + "RadicalDisplayStyleVerticalGap", + "RadicalRuleThickness", + "RadicalExtraAscender", + "RadicalKernBeforeDegree", + "RadicalKernAfterDegree", + "RadicalDegreeBottomRaisePercent", + "MinConnectorOverlap", + "SubscriptShiftDownWithSuperscript", + "FractionDelimiterSize", + "FractionDelimiterDisplayStyleSize", + NULL, +}; + +static void dump_intfield(lua_State * L, const char *n, int c) +{ + lua_pushstring(L, n); + lua_pushnumber(L, c); + lua_rawset(L, -3); +} + + +void dump_math_kerns(lua_State * L, charinfo * co, int l, int id) +{ + int i; + for (i = 0; i < l; i++) { + lua_newtable(L); + /* *INDENT-OFF* */ + if (id==top_left_kern) { + dump_intfield(L, "height", co->top_left_math_kern_array[(2*i)]); + dump_intfield(L, "kern", co->top_left_math_kern_array[(2*i)+1]); + } else if (id==top_right_kern) { + dump_intfield(L, "height", co->top_right_math_kern_array[(2*i)]); + dump_intfield(L, "kern", co->top_right_math_kern_array[(2*i)+1]); + } else if (id==bottom_right_kern) { + dump_intfield(L, "height", co->bottom_right_math_kern_array[(2*i)]); + dump_intfield(L, "kern", co->bottom_right_math_kern_array[(2*i)+1]); + } else if (id==bottom_left_kern) { + dump_intfield(L, "height", co->bottom_left_math_kern_array[(2*i)]); + dump_intfield(L, "kern", co->bottom_left_math_kern_array[(2*i)+1]); + } + /* *INDENT-ON* */ + lua_rawseti(L, -2, (i + 1)); + } +} + + +void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co) +{ + int i, j; + liginfo *l; + kerninfo *ki; + + lua_createtable(L, 0, 10); + + lua_pushstring(L, "width"); + lua_pushnumber(L, get_charinfo_width(co)); + lua_rawset(L, -3); + + lua_pushstring(L, "height"); + lua_pushnumber(L, get_charinfo_height(co)); + lua_rawset(L, -3); + + lua_pushstring(L, "depth"); + lua_pushnumber(L, get_charinfo_depth(co)); + lua_rawset(L, -3); + + lua_pushstring(L, "italic"); + lua_pushnumber(L, get_charinfo_italic(co)); + lua_rawset(L, -3); + + lua_pushstring(L, "top_accent"); + lua_pushnumber(L, get_charinfo_top_accent(co)); + lua_rawset(L, -3); + + lua_pushstring(L, "bot_accent"); + lua_pushnumber(L, get_charinfo_bot_accent(co)); + lua_rawset(L, -3); + + + if (get_charinfo_ef(co) != 0) { + lua_pushstring(L, "expansion_factor"); + lua_pushnumber(L, get_charinfo_ef(co)); + lua_rawset(L, -3); + } + + if (get_charinfo_lp(co) != 0) { + lua_pushstring(L, "left_protruding"); + lua_pushnumber(L, get_charinfo_lp(co)); + lua_rawset(L, -3); + } + + if (get_charinfo_lp(co) != 0) { + lua_pushstring(L, "right_protruding"); + lua_pushnumber(L, get_charinfo_rp(co)); + lua_rawset(L, -3); + } + + + if (font_encodingbytes(f) == 2) { + lua_pushstring(L, "index"); + lua_pushnumber(L, get_charinfo_index(co)); + lua_rawset(L, -3); + } + + if (get_charinfo_name(co) != NULL) { + lua_pushstring(L, "name"); + lua_pushstring(L, get_charinfo_name(co)); + lua_rawset(L, -3); + } + + if (get_charinfo_tounicode(co) != NULL) { + lua_pushstring(L, "tounicode"); + lua_pushstring(L, get_charinfo_tounicode(co)); + lua_rawset(L, -3); + } + + if (get_charinfo_tag(co) == list_tag) { + lua_pushstring(L, "next"); + lua_pushnumber(L, get_charinfo_remainder(co)); + lua_rawset(L, -3); + } + + lua_pushstring(L, "used"); + lua_pushboolean(L, (get_charinfo_used(co) ? true : false)); + lua_rawset(L, -3); + + if (get_charinfo_tag(co) == ext_tag) { + extinfo *h; + h = get_charinfo_hor_variants(co); + if (h != NULL) { + int i = 1; + lua_newtable(L); + while (h != NULL) { + lua_createtable(L, 0, 5); + dump_intfield(L, "glyph", h->glyph); + dump_intfield(L, "extender", h->extender); + dump_intfield(L, "start", h->start_overlap); + dump_intfield(L, "end", h->end_overlap); + dump_intfield(L, "advance", h->advance); + lua_rawseti(L, -2, i); + i++; + h = h->next; + } + lua_setfield(L, -2, "horiz_variants"); + } + h = get_charinfo_vert_variants(co); + if (h != NULL) { + int i = 1; + lua_newtable(L); + while (h != NULL) { + lua_createtable(L, 0, 5); + dump_intfield(L, "glyph", h->glyph); + dump_intfield(L, "extender", h->extender); + dump_intfield(L, "start", h->start_overlap); + dump_intfield(L, "end", h->end_overlap); + dump_intfield(L, "advance", h->advance); + lua_rawseti(L, -2, i); + i++; + h = h->next; + } + lua_setfield(L, -2, "vert_variants"); + } + } + ki = get_charinfo_kerns(co); + if (ki != NULL) { + lua_pushstring(L, "kerns"); + lua_createtable(L, 10, 1); + for (i = 0; !kern_end(ki[i]); i++) { + if (kern_char(ki[i]) == right_boundarychar) { + lua_pushstring(L, "right_boundary"); + } else { + lua_pushnumber(L, kern_char(ki[i])); + } + lua_pushnumber(L, kern_kern(ki[i])); + lua_rawset(L, -3); + } + lua_rawset(L, -3); + } + l = get_charinfo_ligatures(co); + if (l != NULL) { + lua_pushstring(L, "ligatures"); + lua_createtable(L, 10, 1); + for (i = 0; !lig_end(l[i]); i++) { + if (lig_char(l[i]) == right_boundarychar) { + lua_pushstring(L, "right_boundary"); + } else { + lua_pushnumber(L, lig_char(l[i])); + } + lua_createtable(L, 0, 2); + lua_pushstring(L, "type"); + lua_pushnumber(L, lig_type(l[i])); + lua_rawset(L, -3); + lua_pushstring(L, "char"); + lua_pushnumber(L, lig_replacement(l[i])); + lua_rawset(L, -3); + lua_rawset(L, -3); + } + lua_rawset(L, -3); + } + + lua_newtable(L); + + i = get_charinfo_math_kerns(co, top_right_kern); + j = 0; + if (i > 0) { + j++; + lua_newtable(L); + dump_math_kerns(L, co, i, top_right_kern); + lua_setfield(L, -2, "top_right"); + } + i = get_charinfo_math_kerns(co, top_left_kern); + if (i > 0) { + j++; + lua_newtable(L); + dump_math_kerns(L, co, i, top_left_kern); + lua_setfield(L, -2, "top_left"); + } + i = get_charinfo_math_kerns(co, bottom_right_kern); + if (i > 0) { + j++; + lua_newtable(L); + dump_math_kerns(L, co, i, bottom_right_kern); + lua_setfield(L, -2, "bottom_right"); + } + i = get_charinfo_math_kerns(co, bottom_left_kern); + if (i > 0) { + j++; + lua_newtable(L); + dump_math_kerns(L, co, i, bottom_left_kern); + lua_setfield(L, -2, "bottom_left"); + } + if (j > 0) + lua_setfield(L, -2, "mathkern"); + else + lua_pop(L, 1); + +} + +static void write_lua_parameters(lua_State * L, int f) +{ + int k; + lua_newtable(L); + for (k = 1; k <= font_params(f); k++) { + lua_pushnumber(L, font_param(f, k)); + switch (k) { + case slant_code: + lua_setfield(L, -2, "slant"); + break; + case space_code: + lua_setfield(L, -2, "space"); + break; + case space_stretch_code: + lua_setfield(L, -2, "space_stretch"); + break; + case space_shrink_code: + lua_setfield(L, -2, "space_shrink"); + break; + case x_height_code: + lua_setfield(L, -2, "x_height"); + break; + case quad_code: + lua_setfield(L, -2, "quad"); + break; + case extra_space_code: + lua_setfield(L, -2, "extra_space"); + break; + default: + lua_rawseti(L, -2, k); + } + } + lua_setfield(L, -2, "parameters"); +} + +@ @c +static void write_lua_math_parameters(lua_State * L, int f) +{ + int k; + lua_newtable(L); + for (k = 1; k < font_math_params(f); k++) { + lua_pushnumber(L, font_math_param(f, k)); + if (k <= MATH_param_max) { + lua_setfield(L, -2, MATH_param_names[k]); + } else { + lua_rawseti(L, -2, k); + } + } + lua_setfield(L, -2, "MathConstants"); +} + + + +int font_to_lua(lua_State * L, int f) +{ + int k; + charinfo *co; + if (font_cache_id(f) > 0) { + /* fetch the table from the registry if it was + saved there by |font_from_lua()| */ + lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f)); + /* fontdimens can be changed from tex code */ + write_lua_parameters(L, f); + return 1; + } + + lua_newtable(L); + lua_pushstring(L, font_name(f)); + lua_setfield(L, -2, "name"); + if (font_area(f) != NULL) { + lua_pushstring(L, font_area(f)); + lua_setfield(L, -2, "area"); + } + if (font_filename(f) != NULL) { + lua_pushstring(L, font_filename(f)); + lua_setfield(L, -2, "filename"); + } + if (font_fullname(f) != NULL) { + lua_pushstring(L, font_fullname(f)); + lua_setfield(L, -2, "fullname"); + } + if (font_psname(f) != NULL) { + lua_pushstring(L, font_psname(f)); + lua_setfield(L, -2, "psname"); + } + if (font_encodingname(f) != NULL) { + lua_pushstring(L, font_encodingname(f)); + lua_setfield(L, -2, "encodingname"); + } + + lua_pushboolean(L, (font_used(f) ? true : false)); + lua_setfield(L, -2, "used"); + + + lua_pushstring(L, font_type_strings[font_type(f)]); + lua_setfield(L, -2, "type"); + lua_pushstring(L, font_format_strings[font_format(f)]); + lua_setfield(L, -2, "format"); + lua_pushstring(L, font_embedding_strings[font_embedding(f)]); + lua_setfield(L, -2, "embedding"); + + lua_pushnumber(L, font_units_per_em(f)); + lua_setfield(L, -2, "units_per_em"); + lua_pushnumber(L, font_size(f)); + lua_setfield(L, -2, "size"); + lua_pushnumber(L, font_dsize(f)); + lua_setfield(L, -2, "designsize"); + lua_pushnumber(L, font_checksum(f)); + lua_setfield(L, -2, "checksum"); + lua_pushnumber(L, font_slant(f)); + lua_setfield(L, -2, "slant"); + lua_pushnumber(L, font_extend(f)); + lua_setfield(L, -2, "extend"); + lua_pushnumber(L, font_natural_dir(f)); + lua_setfield(L, -2, "direction"); + lua_pushnumber(L, font_encodingbytes(f)); + lua_setfield(L, -2, "encodingbytes"); + lua_pushnumber(L, font_tounicode(f)); + lua_setfield(L, -2, "tounicode"); + + /* pdf parameters */ + /* skip the first four for now, that are very much interal */ +#if 0 + if (pdf_font_num(f) != 0) { + lua_pushnumber(L,pdf_font_num(f)); + lua_setfield(L,-2,"pdf_num"); + } + if (pdf_font_blink(f) != 0) { + lua_pushnumber(L,pdf_font_blink(f)); + lua_setfield(L,-2,"pdf_blink"); + } + if (pdf_font_elink(f) != 0) { + lua_pushnumber(L,pdf_font_elink(f)); + lua_setfield(L,-2,"pdf_elink"); + } +#endif + /* the next one is read only */ + if (font_expand_ratio(f) != 0) { + lua_pushnumber(L, font_expand_ratio(f)); + lua_setfield(L, -2, "expand_ratio"); + } + if (font_shrink(f) != 0) { + lua_pushnumber(L, font_shrink(f)); + lua_setfield(L, -2, "shrink"); + } + if (font_stretch(f) != 0) { + lua_pushnumber(L, font_stretch(f)); + lua_setfield(L, -2, "stretch"); + } + if (font_step(f) != 0) { + lua_pushnumber(L, font_step(f)); + lua_setfield(L, -2, "step"); + } + if (font_auto_expand(f) != 0) { + lua_pushboolean(L, font_auto_expand(f)); + lua_setfield(L, -2, "auto_expand"); + } + if (pdf_font_attr(f) != 0) { + char *s = makecstring(pdf_font_attr(f)); + lua_pushstring(L, s); + free(s); + lua_setfield(L, -2, "attributes"); + } + + /* params */ + write_lua_parameters(L, f); + write_lua_math_parameters(L, f); + + /* chars */ + lua_createtable(L, font_tables[f]->charinfo_size, 0); /* all characters */ + + if (has_left_boundary(f)) { + co = get_charinfo(f, left_boundarychar); + font_char_to_lua(L, f, co); + lua_setfield(L, -2, "left_boundary"); + } + if (has_right_boundary(f)) { + co = get_charinfo(f, right_boundarychar); + font_char_to_lua(L, f, co); + lua_setfield(L, -2, "right_boundary"); + } + + for (k = font_bc(f); k <= font_ec(f); k++) { + if (quick_char_exists(f, k)) { + lua_pushnumber(L, k); + co = get_charinfo(f, k); + font_char_to_lua(L, f, co); + lua_rawset(L, -3); + } + } + lua_setfield(L, -2, "characters"); + + if (font_cache_id(f) == 0) { /* renew */ + int r; + lua_pushvalue(L, -1); + r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */ + set_font_cache_id(f, r); + } + return 1; +} + +static int count_hash_items(lua_State * L, int name_index) +{ + int n = -1; + lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); + lua_rawget(L, -2); + if (!lua_isnil(L, -1)) { + if (lua_istable(L, -1)) { + n = 0; + /* now find the number */ + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + n++; + lua_pop(L, 1); + } + } + } + lua_pop(L, 1); + return n; +} + +@ @c +#define streq(a,b) (strcmp(a,b)==0) + +#define append_packet(k) { cpackets[np++] = (eight_bits)(k); } + +#define do_store_four(l) { \ + append_packet((l&0xFF000000)>>24); \ + append_packet((l&0x00FF0000)>>16); \ + append_packet((l&0x0000FF00)>>8); \ + append_packet((l&0x000000FF)); } + +/* +*/ + +#define lua_roundnumber(a,b) (int)floor((double)lua_tonumber(L,-1)+0.5) + +static int numeric_field(lua_State * L, const char *name, int dflt) +{ + int i = dflt; + lua_pushstring(L, name); + lua_rawget(L, -2); + if (lua_isnumber(L, -1)) { + i = lua_roundnumber(L, -1); + } + lua_pop(L, 1); + return i; +} + +static int n_numeric_field(lua_State * L, int name_index, int dflt) +{ + register int i = dflt; + lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L, -2); + if (lua_type(L, -1) == LUA_TNUMBER) { + i = lua_roundnumber(L, -1); + } + lua_pop(L, 1); + return i; +} + + +static int enum_field(lua_State * L, const char *name, int dflt, + const char **values) +{ + int k; + const char *s; + int i = dflt; + lua_pushstring(L, name); + lua_rawget(L, -2); + if (lua_isnumber(L, -1)) { + lua_number2int(i, lua_tonumber(L, -1)); + } else if (lua_isstring(L, -1)) { + s = lua_tostring(L, -1); + k = 0; + while (values[k] != NULL) { + if (strcmp(values[k], s) == 0) { + i = k; + break; + } + k++; + } + } + lua_pop(L, 1); + return i; +} + +static int boolean_field(lua_State * L, const char *name, int dflt) +{ + int i = dflt; + lua_pushstring(L, name); + lua_rawget(L, -2); + if (lua_isboolean(L, -1)) { + i = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return i; +} + +static int n_boolean_field(lua_State * L, int name_index, int dflt) +{ + int i = dflt; + lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L, -2); + if (lua_isboolean(L, -1)) { + i = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return i; +} + + +static char *string_field(lua_State * L, const char *name, const char *dflt) +{ + char *i; + lua_pushstring(L, name); + lua_rawget(L, -2); + if (lua_isstring(L, -1)) { + i = xstrdup(lua_tostring(L, -1)); + } else if (dflt == NULL) { + i = NULL; + } else { + i = xstrdup(dflt); + } + lua_pop(L, 1); + return i; +} + +static char *n_string_field(lua_State * L, int name_index, char *dflt) +{ + char *i; + lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L, -2); + if (lua_isstring(L, -1)) { + i = xstrdup(lua_tostring(L, -1)); + } else if (dflt == NULL) { + i = NULL; + } else { + i = xstrdup(dflt); + } + lua_pop(L, 1); + return i; +} + +#define init_luaS_index(a) do { \ + lua_pushliteral(L,#a); \ + luaS_##a##_ptr = lua_tostring(L,-1); \ + luaS_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \ + } while (0) + +#define make_luaS_index(a) \ + static int luaS_##a##_index = 0; \ + static const char * luaS_##a##_ptr = NULL + +#define luaS_index(a) luaS_##a##_index + +#define luaS_ptr_eq(a,b) (a==luaS_##b##_ptr) + +make_luaS_index(width); +make_luaS_index(height); +make_luaS_index(depth); +make_luaS_index(italic); +make_luaS_index(top_accent); +make_luaS_index(bot_accent); +make_luaS_index(index); +make_luaS_index(left_protruding); +make_luaS_index(right_protruding); +make_luaS_index(expansion_factor); +make_luaS_index(top); +make_luaS_index(bot); +make_luaS_index(rep); +make_luaS_index(mid); +make_luaS_index(next); +make_luaS_index(used); +make_luaS_index(name); +make_luaS_index(tounicode); +make_luaS_index(font); +make_luaS_index(char); +make_luaS_index(slot); +make_luaS_index(comment); +make_luaS_index(push); +make_luaS_index(pop); +make_luaS_index(rule); +make_luaS_index(right); +make_luaS_index(node); +make_luaS_index(down); +make_luaS_index(special); +make_luaS_index(image); +make_luaS_index(slant); +make_luaS_index(space); +make_luaS_index(space_stretch); +make_luaS_index(space_shrink); +make_luaS_index(x_height); +make_luaS_index(quad); +make_luaS_index(extra_space); +make_luaS_index(left_boundary); +make_luaS_index(right_boundary); +make_luaS_index(kerns); +make_luaS_index(ligatures); +make_luaS_index(fonts); +make_luaS_index(extender); +make_luaS_index(start); +make_luaS_index(end); +make_luaS_index(advance); +make_luaS_index(glyph); +make_luaS_index(extensible); +make_luaS_index(horiz_variants); +make_luaS_index(vert_variants); +make_luaS_index(mathkern); +make_luaS_index(commands); + +void init_font_string_pointers(lua_State * L) +{ + init_luaS_index(width); + init_luaS_index(height); + init_luaS_index(depth); + init_luaS_index(italic); + init_luaS_index(top_accent); + init_luaS_index(bot_accent); + init_luaS_index(index); + init_luaS_index(left_protruding); + init_luaS_index(right_protruding); + init_luaS_index(expansion_factor); + init_luaS_index(top); + init_luaS_index(bot); + init_luaS_index(rep); + init_luaS_index(mid); + init_luaS_index(next); + init_luaS_index(used); + init_luaS_index(name); + init_luaS_index(tounicode); + init_luaS_index(font); + init_luaS_index(char); + init_luaS_index(slot); + init_luaS_index(comment); + init_luaS_index(push); + init_luaS_index(pop); + init_luaS_index(rule); + init_luaS_index(right); + init_luaS_index(node); + init_luaS_index(down); + init_luaS_index(special); + init_luaS_index(image); + + init_luaS_index(slant); + init_luaS_index(space); + init_luaS_index(space_stretch); + init_luaS_index(space_shrink); + init_luaS_index(x_height); + init_luaS_index(quad); + init_luaS_index(extra_space); + + init_luaS_index(left_boundary); + init_luaS_index(right_boundary); + init_luaS_index(kerns); + init_luaS_index(ligatures); + init_luaS_index(fonts); + + init_luaS_index(extender); + init_luaS_index(start); + init_luaS_index(end); + init_luaS_index(advance); + init_luaS_index(glyph); + + init_luaS_index(extensible); + init_luaS_index(horiz_variants); + init_luaS_index(vert_variants); + init_luaS_index(mathkern); + init_luaS_index(commands); + +} + +static int count_char_packet_bytes(lua_State * L) +{ + register int i; + register int l = 0; + int ff = 0; + for (i = 1; i <= (int) lua_objlen(L, -1); i++) { + lua_rawgeti(L, -1, i); + if (lua_istable(L, -1)) { + lua_rawgeti(L, -1, 1); + if (lua_isstring(L, -1)) { + const char *s = lua_tostring(L, -1); + if (luaS_ptr_eq(s, font)) { + l += 5; + ff = 1; + } else if (luaS_ptr_eq(s, char)) { + if (ff == 0) { + l += 5; + } + l += 5; + ff = 1; + } else if (luaS_ptr_eq(s, slot)) { + l += 10; + ff = 1; + } else if (luaS_ptr_eq(s, comment)) {; + } else if (luaS_ptr_eq(s, push) || luaS_ptr_eq(s, pop)) { + l++; + } else if (luaS_ptr_eq(s, rule)) { + l += 9; + } else if (luaS_ptr_eq(s, right) || + luaS_ptr_eq(s, node) || luaS_ptr_eq(s, down)) { + l += 5; + } else if (luaS_ptr_eq(s, special)) { + size_t len; + lua_rawgeti(L, -2, 2); + (void) lua_tolstring(L, -1, &len); + lua_pop(L, 1); + if (len > 0) { + l = (int) (l + 5 + (int) len); + } + } else if (luaS_ptr_eq(s, image)) { + l += 5; + } else { + fprintf(stdout, "unknown packet command %s!\n", s); + } + } else { + fprintf(stdout, "no packet command!\n"); + } + lua_pop(L, 1); /* command name */ + } + lua_pop(L, 1); /* item */ + } + return l; +} + + + +scaled sp_to_dvi(halfword sp, halfword atsize) +{ + double result, mult; + mult = (double) (atsize / 65536.0); + result = (double) (sp * 16.0); + return floor(result / mult); +} + +@ @c +static void +read_char_packets(lua_State * L, int *l_fonts, charinfo * co, int atsize) +{ + int i, n, m; + size_t l; + int cmd; + const char *s; + eight_bits *cpackets; + int ff = 0; + int np = 0; + int max_f = 0; + int pc = count_char_packet_bytes(L); + if (pc <= 0) + return; + assert(l_fonts != NULL); + assert(l_fonts[1] != 0); + while (l_fonts[(max_f + 1)] != 0) + max_f++; + + cpackets = xmalloc((unsigned) (pc + 1)); + for (i = 1; i <= (int) lua_objlen(L, -1); i++) { + lua_rawgeti(L, -1, i); + if (lua_istable(L, -1)) { + /* fetch the command code */ + lua_rawgeti(L, -1, 1); + if (lua_isstring(L, -1)) { + s = lua_tostring(L, -1); + cmd = 0; + if (luaS_ptr_eq(s, font)) { + cmd = packet_font_code; + } else if (luaS_ptr_eq(s, char)) { + cmd = packet_char_code; + if (ff == 0) { + append_packet(packet_font_code); + ff = l_fonts[1]; + do_store_four(ff); + } + } else if (luaS_ptr_eq(s, slot)) { + cmd = packet_nop_code; + lua_rawgeti(L, -2, 2); + n = (int) lua_tointeger(L, -1); + ff = (n > max_f ? l_fonts[1] : l_fonts[n]); + lua_rawgeti(L, -3, 3); + n = (int) lua_tointeger(L, -1); + lua_pop(L, 2); + append_packet(packet_font_code); + do_store_four(ff); + append_packet(packet_char_code); + do_store_four(n); + } else if (luaS_ptr_eq(s, comment)) { + cmd = packet_nop_code; + } else if (luaS_ptr_eq(s, node)) { + cmd = packet_node_code; + } else if (luaS_ptr_eq(s, push)) { + cmd = packet_push_code; + } else if (luaS_ptr_eq(s, pop)) { + cmd = packet_pop_code; + } else if (luaS_ptr_eq(s, rule)) { + cmd = packet_rule_code; + } else if (luaS_ptr_eq(s, right)) { + cmd = packet_right_code; + } else if (luaS_ptr_eq(s, down)) { + cmd = packet_down_code; + } else if (luaS_ptr_eq(s, special)) { + cmd = packet_special_code; + } else if (luaS_ptr_eq(s, image)) { + cmd = packet_image_code; + } + + switch (cmd) { + case packet_push_code: + case packet_pop_code: + append_packet(cmd); + break; + case packet_font_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); + n = (int) lua_tointeger(L, -1); + ff = (n > max_f ? l_fonts[1] : l_fonts[n]); + do_store_four(ff); + lua_pop(L, 1); + break; + case packet_node_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); + n = copy_node_list(nodelist_from_lua(L)); + do_store_four(n); + lua_pop(L, 1); + break; + case packet_char_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); + n = (int) lua_tointeger(L, -1); + do_store_four(n); + lua_pop(L, 1); + break; + case packet_right_code: + case packet_down_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); + n = (int) lua_tointeger(L, -1); + do_store_four(sp_to_dvi(n, atsize)); + lua_pop(L, 1); + break; + case packet_rule_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); + n = (int) lua_tointeger(L, -1); + do_store_four(sp_to_dvi(n, atsize)); + lua_rawgeti(L, -3, 3); + n = (int) lua_tointeger(L, -1); + do_store_four(sp_to_dvi(n, atsize)); + lua_pop(L, 2); + break; + case packet_special_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); + s = lua_tolstring(L, -1, &l); + if (l > 0) { + do_store_four(l); + m = (int) l; + while (m > 0) { + n = *s++; + m--; + append_packet(n); + } + } + lua_pop(L, 1); + break; + case packet_image_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); /* img/imgtable? ... */ + if (lua_istable(L, -1)) { /* imgtable ... */ + lua_getglobal(L, "img"); /* imglib imgtable ... */ + lua_pushstring(L, "new"); /* `new' imglib imgtable ... */ + lua_gettable(L, -2); /* f imglib imgtable ... */ + lua_insert(L, -3); /* imglib imgtable f ... */ + lua_pop(L, 1); /* imgtable f ... */ + lua_call(L, 1, 1); + } /* img ... */ + luaL_checkudata(L, -1, TYPE_IMG); /* img ... --- just typecheck */ + n = luaL_ref(L, LUA_GLOBALSINDEX); /* ... */ + do_store_four(n); + break; + case packet_nop_code: + break; + default: + fprintf(stdout, + "Unknown char packet code %s (char %d in font %s)\n", + s, (int) c, font_name(f)); + } + } + lua_pop(L, 1); /* command code */ + } else { + fprintf(stdout, + "Found a `commands' item that is not a table (char %d in font %s)\n", + (int) c, font_name(f)); + } + lua_pop(L, 1); /* command table */ + } + append_packet(packet_end_code); + set_charinfo_packets(co, cpackets); + return; +} + + +@ @c +static void read_lua_cidinfo(lua_State * L, int f) +{ + int i; + char *s; + lua_getfield(L, -1, "cidinfo"); + if (lua_istable(L, -1)) { + i = numeric_field(L, "version", 0); + set_font_cidversion(f, i); + i = numeric_field(L, "supplement", 0); + set_font_cidsupplement(f, i); + s = string_field(L, "registry", "Adobe"); /* Adobe-Identity-0 */ + set_font_cidregistry(f, s); + s = string_field(L, "ordering", "Identity"); + set_font_cidordering(f, s); + } + lua_pop(L, 1); +} + + +@ @c +static void read_lua_parameters(lua_State * L, int f) +{ + int i, n; + const char *s; + lua_getfield(L, -1, "parameters"); + if (lua_istable(L, -1)) { + /* the number of parameters is the max(IntegerKeys(L)),7) */ + n = 7; + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L, -2)) { + lua_number2int(i, lua_tonumber(L, -2)); + if (i > n) + n = i; + } + lua_pop(L, 1); /* pop value */ + } + if (n > 7) + set_font_params(f, n); + /* sometimes it is handy to have all integer keys */ + for (i = 1; i <= 7; i++) { + lua_rawgeti(L, -1, i); + if (lua_isnumber(L, -1)) { + n = lua_roundnumber(L, -1); + set_font_param(f, i, n); + } + lua_pop(L, 1); + } + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L, -2)) { + i = (int) lua_tointeger(L, -2); + if (i >= 8) { + n = (lua_isnumber(L, -1) ? lua_roundnumber(L, -1) : 0); + set_font_param(f, i, n); + } + } else if (lua_isstring(L, -2)) { + s = lua_tostring(L, -2); + n = (lua_isnumber(L, -1) ? lua_roundnumber(L, -1) : 0); + if (luaS_ptr_eq(s, slant)) { + set_font_param(f, slant_code, n); + } else if (luaS_ptr_eq(s, space)) { + set_font_param(f, space_code, n); + } else if (luaS_ptr_eq(s, space_stretch)) { + set_font_param(f, space_stretch_code, n); + } else if (luaS_ptr_eq(s, space_shrink)) { + set_font_param(f, space_shrink_code, n); + } else if (luaS_ptr_eq(s, x_height)) { + set_font_param(f, x_height_code, n); + } else if (luaS_ptr_eq(s, quad)) { + set_font_param(f, quad_code, n); + } else if (luaS_ptr_eq(s, extra_space)) { + set_font_param(f, extra_space_code, n); + } + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + +} + +@ @c +static void read_lua_math_parameters(lua_State * L, int f) +{ + int i = 0, n = 0; + lua_getfield(L, -1, "MathConstants"); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L, -2)) { + lua_number2int(i, lua_tonumber(L, -2)); + } else if (lua_isstring(L, -2)) { + i = luaL_checkoption(L, -2, NULL, MATH_param_names); + } + lua_number2int(n, lua_tonumber(L, -1)); + if (i != 0) { + set_font_math_param(f, i, n); + } + lua_pop(L, 1); /* pop value */ + } + } + lua_pop(L, 1); +} + +@ @c +#define MIN_INF -0x7FFFFFFF + + +static void store_math_kerns(lua_State * L, charinfo * co, int id) +{ + int l, k, i; + scaled ht, krn; + if (lua_istable(L, -1) && ((k = (int) lua_objlen(L, -1)) > 0)) { + for (l = 0; l < k; l++) { + lua_rawgeti(L, -1, (l + 1)); + if (lua_istable(L, -1)) { + lua_getfield(L, -1, "height"); + if (lua_isnumber(L, -1)) { + lua_number2int(i, lua_tonumber(L, -1)); + ht = (scaled) i; + } else { + ht = MIN_INF; + } + lua_pop(L, 1); + lua_getfield(L, -1, "kern"); + if (lua_isnumber(L, -1)) { + lua_number2int(i, lua_tonumber(L, -1)); + krn = (scaled) i; + } else { + krn = MIN_INF; + } + lua_pop(L, 1); + if (krn > MIN_INF && ht > MIN_INF) + add_charinfo_math_kern(co, id, ht, krn); + } + lua_pop(L, 1); + } + } +} + +@ @c +void +font_char_from_lua(lua_State * L, internal_font_number f, int i, + int *l_fonts, boolean has_math) +{ + int k, r, t; + charinfo *co; + kerninfo *ckerns; + liginfo *cligs; + scaled j; + const char *s; + int nl = 0; /* number of ligature table items */ + int nk = 0; /* number of kern table items */ + int ctr = 0; + int atsize = font_size(f); + if (lua_istable(L, -1)) { + co = get_charinfo(f, i); + set_charinfo_tag(co, 0); + j = n_numeric_field(L, luaS_width_index, 0); + set_charinfo_width(co, j); + j = n_numeric_field(L, luaS_height_index, 0); + set_charinfo_height(co, j); + j = n_numeric_field(L, luaS_depth_index, 0); + set_charinfo_depth(co, j); + j = n_numeric_field(L, luaS_italic_index, 0); + set_charinfo_italic(co, j); + j = n_numeric_field(L, luaS_index_index, 0); + set_charinfo_index(co, j); + j = n_numeric_field(L, luaS_expansion_factor_index, 0); + set_charinfo_ef(co, j); + j = n_numeric_field(L, luaS_left_protruding_index, 0); + set_charinfo_lp(co, j); + j = n_numeric_field(L, luaS_right_protruding_index, 0); + set_charinfo_rp(co, j); + k = n_boolean_field(L, luaS_used_index, 0); + set_charinfo_used(co, k); + s = n_string_field(L, luaS_name_index, NULL); + if (s != NULL) + set_charinfo_name(co, xstrdup(s)); + else + set_charinfo_name(co, NULL); + s = n_string_field(L, luaS_tounicode_index, NULL); + if (s != NULL) + set_charinfo_tounicode(co, xstrdup(s)); + else + set_charinfo_tounicode(co, NULL); + + if (has_math) { + j = n_numeric_field(L, luaS_top_accent_index, 0); + set_charinfo_top_accent(co, j); + j = n_numeric_field(L, luaS_bot_accent_index, 0); + set_charinfo_bot_accent(co, j); + k = n_numeric_field(L, luaS_next_index, -1); + if (k >= 0) { + set_charinfo_tag(co, list_tag); + set_charinfo_remainder(co, k); + } + + lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_extensible_index); + lua_rawget(L, -2); + if (lua_istable(L, -1)) { + int top, bot, mid, rep; + top = n_numeric_field(L, luaS_top_index, 0); + bot = n_numeric_field(L, luaS_bot_index, 0); + mid = n_numeric_field(L, luaS_mid_index, 0); + rep = n_numeric_field(L, luaS_rep_index, 0); + if (top != 0 || bot != 0 || mid != 0 || rep != 0) { + set_charinfo_tag(co, ext_tag); + set_charinfo_extensible(co, top, bot, mid, rep); + } else { + pdftex_warn + ("lua-loaded font %s char [U+%X] has an invalid extensible field!", + font_name(f), (int) i); + } + } + lua_pop(L, 1); + + lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_horiz_variants_index); + lua_rawget(L, -2); + if (lua_istable(L, -1)) { + int glyph, startconnect, endconnect, advance, extender; + extinfo *h; + set_charinfo_tag(co, ext_tag); + set_charinfo_hor_variants(co, NULL); + for (k = 1;; k++) { + lua_rawgeti(L, -1, k); + if (lua_istable(L, -1)) { + glyph = n_numeric_field(L, luaS_glyph_index, 0); + extender = n_numeric_field(L, luaS_extender_index, 0); + startconnect = n_numeric_field(L, luaS_start_index, 0); + endconnect = n_numeric_field(L, luaS_end_index, 0); + advance = n_numeric_field(L, luaS_advance_index, 0); + h = new_variant(glyph, startconnect, endconnect, + advance, extender); + add_charinfo_hor_variant(co, h); + lua_pop(L, 1); + } else { + lua_pop(L, 1); + break; + } + } + } + lua_pop(L, 1); + + lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_vert_variants_index); + lua_rawget(L, -2); + if (lua_istable(L, -1)) { + int glyph, startconnect, endconnect, advance, extender; + extinfo *h; + set_charinfo_tag(co, ext_tag); + set_charinfo_vert_variants(co, NULL); + for (k = 1;; k++) { + lua_rawgeti(L, -1, k); + if (lua_istable(L, -1)) { + glyph = n_numeric_field(L, luaS_glyph_index, 0); + extender = n_numeric_field(L, luaS_extender_index, 0); + startconnect = n_numeric_field(L, luaS_start_index, 0); + endconnect = n_numeric_field(L, luaS_end_index, 0); + advance = n_numeric_field(L, luaS_advance_index, 0); + h = new_variant(glyph, startconnect, endconnect, + advance, extender); + add_charinfo_vert_variant(co, h); + lua_pop(L, 1); + } else { + lua_pop(L, 1); + break; + } + } + } + lua_pop(L, 1); + +/* Here is a complete example: + + |["mathkern"]={| + |["bottom_left"] ={ { ["height"]=420, ["kern"]=80 }, { ["height"]=520, ["kern"]=4 } },| + |["bottom_right"]={ { ["height"]=0, ["kern"]=48 } },| + |["top_left"] ={ { ["height"]=620, ["kern"]=0 }, { ["height"]=720, ["kern"]=-80 } },| + |["top_right"] ={ { ["height"]=676, ["kern"]=115 }, { ["height"]=776, ["kern"]=45 } },| + |}| + */ + lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_mathkern_index); + lua_rawget(L, -2); + if (lua_istable(L, -1)) { + lua_getfield(L, -1, "top_left"); + store_math_kerns(L, co, top_left_kern); + lua_pop(L, 1); + lua_getfield(L, -1, "top_right"); + store_math_kerns(L, co, top_right_kern); + lua_pop(L, 1); + lua_getfield(L, -1, "bottom_right"); + store_math_kerns(L, co, bottom_right_kern); + lua_pop(L, 1); + lua_getfield(L, -1, "bottom_left"); + store_math_kerns(L, co, bottom_left_kern); + lua_pop(L, 1); + } + lua_pop(L, 1); + } + /* end of |has_math| */ + nk = count_hash_items(L, luaS_index(kerns)); + if (nk > 0) { + ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo)); + lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(kerns)); + lua_rawget(L, -2); + if (lua_istable(L, -1)) { /* there are kerns */ + ctr = 0; + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + k = non_boundarychar; + if (lua_isnumber(L, -2)) { + lua_number2int(k, lua_tonumber(L, -2)); /* adjacent char */ + if (k < 0) + k = non_boundarychar; + } else if (lua_isstring(L, -2)) { + s = lua_tostring(L, -2); + if (luaS_ptr_eq(s, right_boundary)) { + k = right_boundarychar; + if (!has_right_boundary(f)) + set_right_boundary(f, + get_charinfo(f, + right_boundarychar)); + } + } + j = lua_roundnumber(L, -1); /* movement */ + if (k != non_boundarychar) { + set_kern_item(ckerns[ctr], k, j); + ctr++; + } else { + pdftex_warn + ("lua-loaded font %s char [U+%X] has an invalid kern field!", + font_name(f), (int) i); + } + lua_pop(L, 1); + } + /* guard against empty tables */ + if (ctr > 0) { + set_kern_item(ckerns[ctr], end_kern, 0); + set_charinfo_kerns(co, ckerns); + } else { + pdftex_warn + ("lua-loaded font %s char [U+%X] has an invalid kerns field!", + font_name(f), (int) i); + } + } + lua_pop(L, 1); + } + + /* packet commands */ + lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_commands_index); + lua_rawget(L, -2); + if (lua_istable(L, -1)) { + lua_pushnil(L); /* first key */ + if (lua_next(L, -2) != 0) { + lua_pop(L, 2); + read_char_packets(L, (int *) l_fonts, co, atsize); + } + } + lua_pop(L, 1); + + /* ligatures */ + nl = count_hash_items(L, luaS_index(ligatures)); + + if (nl > 0) { + cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo)); + lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(ligatures)); + lua_rawget(L, -2); + if (lua_istable(L, -1)) { /* do ligs */ + ctr = 0; + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + k = non_boundarychar; + if (lua_isnumber(L, -2)) { + lua_number2int(k, lua_tonumber(L, -2)); /* adjacent char */ + if (k < 0) { + k = non_boundarychar; + } + } else if (lua_isstring(L, -2)) { + s = lua_tostring(L, -2); + if (luaS_ptr_eq(s, right_boundary)) { + k = right_boundarychar; + if (!has_right_boundary(f)) + set_right_boundary(f, + get_charinfo(f, + right_boundarychar)); + } + } + r = -1; + if (lua_istable(L, -1)) { + r = n_numeric_field(L, luaS_char_index, -1); /* ligature */ + } + if (r != -1 && k != non_boundarychar) { + t = enum_field(L, "type", 0, ligature_type_strings); + set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, + r); + ctr++; + } else { + pdftex_warn + ("lua-loaded font %s char [U+%X] has an invalid ligature field!", + font_name(f), (int) i); + } + lua_pop(L, 1); /* iterator value */ + } + /* guard against empty tables */ + if (ctr > 0) { + set_ligature_item(cligs[ctr], 0, end_ligature, 0); + set_charinfo_ligatures(co, cligs); + } else { + pdftex_warn + ("lua-loaded font %s char [U+%X] has an invalid ligatures field!", + font_name(f), (int) i); + } + } + lua_pop(L, 1); /* ligatures table */ + } + } +} + + + +@ The caller has to fix the state of the lua stack when there is an error! + +@c +int font_from_lua(lua_State * L, int f) +{ + int i, n, r, t; + int s_top; /* lua stack top */ + int bc; /* first char index */ + int ec; /* last char index */ + char *s; + const char *ss; + int *l_fonts = NULL; + int save_ref = 1; /* unneeded, really */ + boolean no_math = false; + + /* will we save a cache of the luat table? */ + s = string_field(L, "cache", "yes"); + if (strcmp(s, "yes") == 0) + save_ref = 1; + else if (strcmp(s, "no") == 0) + save_ref = -1; + else if (strcmp(s, "renew") == 0) + save_ref = 0; + free(s); + + /* the table is at stack index -1 */ + + if (luaS_width_index == 0) + init_font_string_pointers(L); + + s = string_field(L, "area", ""); + set_font_area(f, s); + s = string_field(L, "filename", NULL); + set_font_filename(f, s); + s = string_field(L, "encodingname", NULL); + set_font_encodingname(f, s); + + s = string_field(L, "name", NULL); + set_font_name(f, s); + s = string_field(L, "fullname", font_name(f)); + set_font_fullname(f, s); + + if (s == NULL) { + pdftex_fail("lua-loaded font [%d] has no name!", f); + return false; + } + s = string_field(L, "psname", NULL); + set_font_psname(f, s); + + i = numeric_field(L, "units_per_em", 0); + set_font_units_per_em(f, i); + i = numeric_field(L, "designsize", 655360); + set_font_dsize(f, i); + i = numeric_field(L, "size", font_dsize(f)); + set_font_size(f, i); + i = numeric_field(L, "checksum", 0); + set_font_checksum(f, (unsigned) i); + i = numeric_field(L, "direction", 0); + set_font_natural_dir(f, i); + i = numeric_field(L, "encodingbytes", 0); + set_font_encodingbytes(f, (char) i); + i = numeric_field(L, "tounicode", 0); + set_font_tounicode(f, (char) i); + + i = numeric_field(L, "extend", 1000); + if (i < FONT_EXTEND_MIN) + i = FONT_EXTEND_MIN; + if (i > FONT_EXTEND_MAX) + i = FONT_EXTEND_MAX; + set_font_extend(f, i); + i = numeric_field(L, "slant", 0); + if (i < FONT_SLANT_MIN) + i = FONT_SLANT_MIN; + if (i > FONT_SLANT_MAX) + i = FONT_SLANT_MAX; + set_font_slant(f, i); + + i = numeric_field(L, "hyphenchar", int_par(default_hyphen_char_code)); + set_hyphen_char(f, i); + i = numeric_field(L, "skewchar", int_par(default_skew_char_code)); + set_skew_char(f, i); + i = boolean_field(L, "used", 0); + set_font_used(f, (char) i); + + s = string_field(L, "attributes", NULL); + if (s != NULL && strlen(s) > 0) { + i = maketexstring(s); + set_pdf_font_attr(f, i); + } + + i = enum_field(L, "type", unknown_font_type, font_type_strings); + set_font_type(f, i); + i = enum_field(L, "format", unknown_format, font_format_strings); + set_font_format(f, i); + i = enum_field(L, "embedding", unknown_embedding, font_embedding_strings); + set_font_embedding(f, i); + if (font_encodingbytes(f) == 0 && + (font_format(f) == opentype_format + || font_format(f) == truetype_format)) { + set_font_encodingbytes(f, 2); + } + + /* now fetch the base fonts, if needed */ + n = count_hash_items(L, luaS_index(fonts)); + if (n > 0) { + l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int))); + memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int))); + lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(fonts)); + lua_rawget(L, -2); + for (i = 1; i <= n; i++) { + lua_rawgeti(L, -1, i); + if (lua_istable(L, -1)) { + lua_getfield(L, -1, "id"); + if (lua_isnumber(L, -1)) { + lua_number2int(l_fonts[i], lua_tonumber(L, -1)); + lua_pop(L, 2); /* pop id and entry */ + continue; + } + lua_pop(L, 1); /* pop id */ + }; + ss = NULL; + if (lua_istable(L, -1)) { + lua_getfield(L, -1, "name"); + if (lua_isstring(L, -1)) { + ss = lua_tostring(L, -1); + } + lua_pop(L, 1); /* pop name */ + } + if (ss != NULL) { + lua_getfield(L, -1, "size"); + t = (lua_isnumber(L, -1) ? lua_roundnumber(L, -1) : -1000); + lua_pop(L, 1); + + /* TODO: the stack is messed up, otherwise this + * explicit resizing would not be needed + */ + s_top = lua_gettop(L); + if (strcmp(font_name(f), ss) == 0) + l_fonts[i] = f; + else + l_fonts[i] = find_font_id(ss, t); + lua_settop(L, s_top); + } else { + pdftex_fail("Invalid local font in font %s!\n", font_name(f)); + } + lua_pop(L, 1); /* pop list entry */ + } + lua_pop(L, 1); /* pop list entry */ + } else { + if (font_type(f) == virtual_font_type) { + pdftex_fail("Invalid local fonts in font %s!\n", font_name(f)); + } else { + l_fonts = xmalloc(3 * sizeof(int)); + l_fonts[0] = 0; + l_fonts[1] = f; + l_fonts[2] = 0; + } + } + + /* parameters */ + no_math = boolean_field(L, "nomath", 0); + read_lua_parameters(L, f); + if (!no_math) { + read_lua_math_parameters(L, f); + } + read_lua_cidinfo(L, f); + + /* characters */ + + lua_getfield(L, -1, "characters"); + if (lua_istable(L, -1)) { + /* find the array size values */ + int num = 0; /* number of charinfo's to add */ + ec = 0; + bc = -1; + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L, -2)) { + i = (int) lua_tointeger(L, -2); + if (i >= 0) { + if (lua_istable(L, -1)) { + num++; + if (i > ec) + ec = i; + if (bc < 0) + bc = i; + if (bc >= 0 && i < bc) + bc = i; + } + } + } + lua_pop(L, 1); + } + if (bc != -1) { +#if 0 + fprintf(stdout,"defined a font at %d with %d-%d\n",f,bc,ec); +#endif + font_malloc_charinfo(f, num); + set_font_bc(f, bc); + set_font_ec(f, ec); + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L, -2)) { + lua_number2int(i, lua_tonumber(L, -2)); + if (i >= 0) { + font_char_from_lua(L, f, i, l_fonts, !no_math); + } + } else if (lua_isstring(L, -2)) { + const char *ss = lua_tostring(L, -2); + if (luaS_ptr_eq(ss, left_boundary)) { + font_char_from_lua(L, f, left_boundarychar, l_fonts, + !no_math); + } else if (luaS_ptr_eq(ss, right_boundary)) { + font_char_from_lua(L, f, right_boundarychar, l_fonts, + !no_math); + } + } + lua_pop(L, 1); + } + lua_pop(L, 1); + + /* handle font expansion last: the |copy_font| routine is called eventually, + and that needs to know |bc| and |ec|. */ + if (font_type(f) != virtual_font_type) { + int fstep = numeric_field(L, "step", 0); + if (fstep < 0) + fstep = 0; + if (fstep > 100) + fstep = 100; + if (fstep != 0) { + int fshrink = numeric_field(L, "shrink", 0); + int fstretch = numeric_field(L, "stretch", 0); + int fexpand = boolean_field(L, "auto_expand", 0); + if (fshrink < 0) + fshrink = 0; + if (fshrink > 500) + fshrink = 500; + fshrink -= (fshrink % fstep); + if (fshrink < 0) + fshrink = 0; + if (fstretch < 0) + fstretch = 0; + if (fstretch > 1000) + fstretch = 1000; + fstretch -= (fstretch % fstep); + if (fstretch < 0) + fstretch = 0; + set_expand_params(f, fexpand, fstretch, fshrink, fstep, 0); + } + } + + } else { /* jikes, no characters */ + pdftex_warn("lua-loaded font [%d] (%s) has no characters!", f, + font_name(f)); + } + + if (save_ref > 0) { + r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */ + set_font_cache_id(f, r); + } else { + lua_pop(L, 1); + set_font_cache_id(f, save_ref); + } + } else { /* jikes, no characters */ + pdftex_warn("lua-loaded font [%d] (%s) has no character table!", f, + font_name(f)); + } + + if (l_fonts != NULL) + free(l_fonts); + return true; +} + + + +@* Ligaturing. + +@c +#define assert_disc(a) \ + assert(pre_break(a)!=null); /* expect |head_node| */ \ + assert(type(pre_break(a))==nesting_node); \ + assert((vlink_pre_break(a)==null && tlink_pre_break(a)==null) || \ + tail_of_list(vlink_pre_break(a))==tlink_pre_break(a)); \ + assert(post_break(a)!=null); /* expect |head_node| */ \ + assert(type(post_break(a))==nesting_node); \ + assert((vlink_post_break(a)==null && tlink_post_break(a)==null) || \ + tail_of_list(vlink_post_break(a))==tlink_post_break(a)); \ + assert(no_break(a)!=null); /* expect |head_node| */ \ + assert(type(no_break(a))==nesting_node); \ + assert((vlink_no_break(a)==null && tlink_no_break(a)==null) || \ + tail_of_list(vlink_no_break(a))==tlink_no_break(a)); + +static void nesting_append(halfword nest, halfword newn) +{ + halfword tail = tlink(nest); + assert(alink(nest) == null); + assert(vlink(newn) == null); + assert(alink(newn) == null); + if (tail == null) { + assert(vlink(nest) == null); + couple_nodes(nest, newn); + } else { + assert(vlink(tail) == null); + assert(tail_of_list(vlink(nest)) == tail); + couple_nodes(tail, newn); + } + tlink(nest) = newn; +} + + +static void nesting_prepend(halfword nest, halfword newn) +{ + halfword head = vlink(nest); + assert(alink(nest) == null); + assert(vlink(newn) == null); + assert(alink(newn) == null); + couple_nodes(nest, newn); + if (head == null) { + assert(tlink(nest) == null); + tlink(nest) = newn; + } else { + assert(alink(head) == nest); + assert(tail_of_list(head) == tlink(nest)); + couple_nodes(newn, head); + } +} + + +static void nesting_prepend_list(halfword nest, halfword newn) +{ + halfword head = vlink(nest); + assert(alink(nest) == null); + assert(alink(newn) == null); + couple_nodes(nest, newn); + if (head == null) { + assert(tlink(nest) == null); + tlink(nest) = tail_of_list(newn); + } else { + halfword tail = tail_of_list(newn); + assert(alink(head) == nest); + assert(tail_of_list(head) == tlink(nest)); + couple_nodes(tail, head); + } +} + + +static int test_ligature(liginfo * lig, halfword left, halfword right) +{ + if (type(left) != glyph_node) + return 0; + assert(type(right) == glyph_node); + if (font(left) != font(right)) + return 0; + if (is_ghost(left) || is_ghost(right)) + return 0; + *lig = get_ligature(font(left), character(left), character(right)); + if (is_valid_ligature(*lig)) { + return 1; + } + return 0; +} + + +static int try_ligature(halfword * frst, halfword fwd) +{ + halfword cur = *frst; + liginfo lig; + if (test_ligature(&lig, cur, fwd)) { + int move_after = (lig_type(lig) & 0x0C) >> 2; + int keep_right = ((lig_type(lig) & 0x01) != 0); + int keep_left = ((lig_type(lig) & 0x02) != 0); + halfword newgl = raw_glyph_node(); + font(newgl) = font(cur); + character(newgl) = lig_replacement(lig); + set_is_ligature(newgl); + + /* below might not be correct in contrived border case. + but we use it only for debugging, so ... */ + if (character(cur) < 0) { + set_is_leftboundary(newgl); + } + if (character(fwd) < 0) { + set_is_rightboundary(newgl); + } + if (character(cur) < 0) { + if (character(fwd) < 0) { + build_attribute_list(newgl); + } else { + add_node_attr_ref(node_attr(fwd)); + node_attr(newgl) = node_attr(fwd); + } + } else { + add_node_attr_ref(node_attr(cur)); + node_attr(newgl) = node_attr(cur); + } + + /* TODO/FIXME if this ligature is consists of another ligature + we should add it's |lig_ptr| to the new glyphs |lig_ptr| (and + cleanup the no longer needed node) LOW PRIORITY */ + /* left side */ + if (keep_left) { + halfword new_first = copy_node(cur); + lig_ptr(newgl) = new_first; + couple_nodes(cur, newgl); + if (move_after) { + move_after--; + cur = newgl; + } + } else { + halfword prev = alink(cur); + uncouple_node(cur); + lig_ptr(newgl) = cur; + assert(prev != null); + couple_nodes(prev, newgl); + cur = newgl; /* as cur has disappeared */ + } + /* right side */ + if (keep_right) { + halfword new_second = copy_node(fwd); + /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */ + couple_nodes(lig_ptr(newgl), new_second); + couple_nodes(newgl, fwd); + if (move_after) { + move_after--; + cur = fwd; + } + } else { + halfword next = vlink(fwd); + uncouple_node(fwd); + /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */ + couple_nodes(lig_ptr(newgl), fwd); + if (next != null) { + couple_nodes(newgl, next); + } + } + + /* check and return */ + *frst = cur; + return 1; + } + return 0; +} + + +@ there shouldn't be any ligatures here - we only add them at the end of + |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing \.{DISC-1} + (we continue with \.{DISC-1}'s |post_| and |no_break|. + +@c +static halfword handle_lig_nest(halfword root, halfword cur) +{ + if (cur == null) + return root; + while (vlink(cur) != null) { + halfword fwd = vlink(cur); + if (type(cur) == glyph_node && type(fwd) == glyph_node && + font(cur) == font(fwd) && try_ligature(&cur, fwd)) + continue; + cur = vlink(cur); + assert(vlink(alink(cur)) == cur); + } + tlink(root) = cur; + return root; +} + + +static halfword handle_lig_word(halfword cur) +{ + halfword right = null; + if (type(cur) == whatsit_node && subtype(cur) == cancel_boundary_node) { + halfword prev = alink(cur); + halfword fwd = vlink(cur); + /* no need to uncouple |cur|, it is freed */ + flush_node(cur); + if (fwd == null) { + vlink(prev) = fwd; + return prev; + } + couple_nodes(prev, fwd); + if (type(fwd) != glyph_node) + return prev; + cur = fwd; + } else if (has_left_boundary(font(cur))) { + halfword prev = alink(cur); + halfword p = new_glyph(font(cur), left_boundarychar); + couple_nodes(prev, p); + couple_nodes(p, cur); + cur = p; + } + if (has_right_boundary(font(cur))) { + right = new_glyph(font(cur), right_boundarychar); + } + while (1) { + /* A glyph followed by ... */ + if (type(cur) == glyph_node) { + halfword fwd = vlink(cur); + if (fwd == null) { /* last character of paragraph */ + if (right == null) + break; + /* \.{--\\par} prohibits use of |couple_nodes| here */ + try_couple_nodes(cur, right); + right = null; + continue; + } + assert(alink(fwd) == cur); + if (type(fwd) == glyph_node) { /* |GLYPH - GLYPH| */ + if (font(cur) != font(fwd)) + break; + if (try_ligature(&cur, fwd)) + continue; + } else if (type(fwd) == disc_node) { /* |GLYPH - DISC| */ + + /* if \.{a{bx}{}{y}} and \.{a+b=>B} convert to \.{{Bx}{}{ay}} */ + halfword pre = vlink_pre_break(fwd); + halfword nob = vlink_no_break(fwd); + halfword next, tail; + liginfo lig; + assert_disc(fwd); + /* Check on: a{b?}{?}{?} and a+b=>B : {B?}{?}{a?} */ + /* Check on: a{?}{?}{b?} and a+b=>B : {a?}{?}{B?} */ + if ((pre != null && type(pre) == glyph_node + && test_ligature(&lig, cur, pre)) + || (nob != null && type(nob) == glyph_node + && test_ligature(&lig, cur, nob))) { + /* move cur from before disc, to skipped part */ + halfword prev = alink(cur); + assert(vlink(prev) == cur); + uncouple_node(cur); + couple_nodes(prev, fwd); + nesting_prepend(no_break(fwd), cur); + /* now ligature the |pre_break| */ + nesting_prepend(pre_break(fwd), copy_node(cur)); + /* As we have removed cur, we need to start again ... */ + cur = prev; + } + /* Check on: a{?}{?}{}b and a+b=>B : {a?}{?b}{B} */ + next = vlink(fwd); + if (nob == null && next != null && type(next) == glyph_node + && test_ligature(&lig, cur, next)) { + /* move |cur| from before |disc| to |no_break| part */ + halfword prev = alink(cur); + assert(alink(next) == fwd); + assert(vlink(prev) == cur); + uncouple_node(cur); + couple_nodes(prev, fwd); + couple_nodes(no_break(fwd), cur); /* we {\it know\/} it's empty */ + /* now copy cur the |pre_break| */ + nesting_prepend(pre_break(fwd), copy_node(cur)); + /* move next from after disc to |no_break| part */ + tail = vlink(next); + uncouple_node(next); + try_couple_nodes(fwd, tail); + couple_nodes(cur, next); /* we {\it know\/} this works */ + tlink(no_break(fwd)) = next; /* and make sure the list is correct */ + /* now copy next to the |post_break| */ + nesting_append(post_break(fwd), copy_node(next)); + /* As we have removed cur, we need to start again ... */ + cur = prev; + } + /* we are finished with the |pre_break| */ + handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd)); + } else if (type(fwd) == whatsit_node + && subtype(fwd) == cancel_boundary_node) { + halfword next = vlink(fwd); + try_couple_nodes(cur, next); + flush_node(fwd); + if (right != null) { + flush_node(right); /* Shame, didn't need it */ + /* no need to reset |right|, we're going to leave the loop anyway */ + } + break; + } else { /* fwd is something unknown */ + if (right == null) + break; + couple_nodes(cur, right); + couple_nodes(right, fwd); + right = null; + continue; + } + /* A discretionary followed by ... */ + } else if (type(cur) == disc_node) { + + assert_disc(cur); + /* If \.{{?}{x}{?}} or \.{{?}{?}{y}} then ... */ + if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) { + halfword prev = 0; + halfword fwd; + liginfo lig; + if (subtype(cur) == select_disc) { + prev = alink(cur); + assert(type(prev) == disc_node + && subtype(prev) == init_disc); + if (vlink_post_break(cur) != null) + handle_lig_nest(post_break(prev), + vlink_post_break(prev)); + if (vlink_no_break(cur) != null) + handle_lig_nest(no_break(prev), vlink_no_break(prev)); + } + if (vlink_post_break(cur) != null) + handle_lig_nest(post_break(cur), vlink_post_break(cur)); + if (vlink_no_break(cur) != null) + handle_lig_nest(no_break(cur), vlink_no_break(cur)); + while ((fwd = vlink(cur)) != null) { + halfword nob, pst, next; + if (type(fwd) != glyph_node) + break; + if (subtype(cur) != select_disc) { + nob = tlink_no_break(cur); + pst = tlink_post_break(cur); + if ((nob == null || !test_ligature(&lig, nob, fwd)) && + (pst == null || !test_ligature(&lig, pst, fwd))) + break; + nesting_append(no_break(cur), copy_node(fwd)); + handle_lig_nest(no_break(cur), nob); + } else { + int dobreak = 0; + nob = tlink_no_break(prev); + pst = tlink_post_break(prev); + if ((nob == null || !test_ligature(&lig, nob, fwd)) && + (pst == null || !test_ligature(&lig, pst, fwd))) + dobreak = 1; + if (!dobreak) { + nesting_append(no_break(prev), copy_node(fwd)); + handle_lig_nest(no_break(prev), nob); + nesting_append(post_break(prev), copy_node(fwd)); + handle_lig_nest(post_break(prev), pst); + } + dobreak = 0; + nob = tlink_no_break(cur); + pst = tlink_post_break(cur); + if ((nob == null || !test_ligature(&lig, nob, fwd)) && + (pst == null || !test_ligature(&lig, pst, fwd))) + dobreak = 1; + if (!dobreak) { + nesting_append(no_break(cur), copy_node(fwd)); + handle_lig_nest(no_break(cur), nob); + } + if (dobreak) + break; + } + next = vlink(fwd); + uncouple_node(fwd); + try_couple_nodes(cur, next); + nesting_append(post_break(cur), fwd); + handle_lig_nest(post_break(cur), pst); + } + if (fwd != null && type(fwd) == disc_node) { + halfword next = vlink(fwd); + if (vlink_no_break(fwd) == null && + vlink_post_break(fwd) == null && + next != null && + type(next) == glyph_node && + ((tlink_post_break(cur) != null && + test_ligature(&lig, tlink_post_break(cur), next)) || + (tlink_no_break(cur) != null && + test_ligature(&lig, tlink_no_break(cur), next)))) { + /* Building an |init_disc| followed by a |select_disc| + \.{{a-}{b}{AB} {-}{}{}} 'c' + */ + halfword last = vlink(next), tail; + uncouple_node(next); + try_couple_nodes(fwd, last); + /* \.{{a-}{b}{AB} {-}{c}{}} */ + nesting_append(post_break(fwd), copy_node(next)); + /* \.{{a-}{b}{AB} {-}{c}{-}} */ + if (vlink_no_break(cur) != null) { + nesting_prepend(no_break(fwd), + copy_node(vlink_pre_break(fwd))); + } + /* \.{{a-}{b}{AB} {b-}{c}{-}} */ + if (vlink_post_break(cur) != null) + nesting_prepend_list(pre_break(fwd), + copy_node_list(vlink_post_break + (cur))); + /* \.{{a-}{b}{AB} {b-}{c}{AB-}} */ + if (vlink_no_break(cur) != null) { + nesting_prepend_list(no_break(fwd), + copy_node_list(vlink_no_break + (cur))); + } + /* \.{{a-}{b}{ABC} {b-}{c}{AB-}} */ + tail = tlink_no_break(cur); + nesting_append(no_break(cur), copy_node(next)); + handle_lig_nest(no_break(cur), tail); + /* \.{{a-}{BC}{ABC} {b-}{c}{AB-}} */ + tail = tlink_post_break(cur); + nesting_append(post_break(cur), next); + handle_lig_nest(post_break(cur), tail); + /* and set the subtypes */ + subtype(cur) = init_disc; + subtype(fwd) = select_disc; + } + } + } + + } else { /* NO GLYPH NOR DISC */ +#if 0 + fprintf(stdout,"This is a %d node\n",type(cur)); + assert(0); /* TODO howcome there can be a glue here? */ +#endif + return cur; + } + /* step-to-next-node */ + { + halfword prev = cur; + /* \.{--\\par} allows |vlink(cur)| to be null */ + cur = vlink(cur); + if (cur != null) { + assert(alink(cur) == prev); + } + } + } + + return cur; +} + +@ Return value is the new tail, head should be a dummy + +@c +halfword handle_ligaturing(halfword head, halfword tail) +{ + halfword save_tail; /* trick to allow explicit |node==null| tests */ + halfword cur, prev; + + if (vlink(head) == null) + return tail; + save_tail = vlink(tail); + vlink(tail) = null; + + /* |if (fix_node_lists)| */ + fix_node_list(head); + + prev = head; + cur = vlink(prev); + + while (cur != null) { + if (type(cur) == glyph_node || + (type(cur) == whatsit_node + && subtype(cur) == cancel_boundary_node)) { + cur = handle_lig_word(cur); + } + prev = cur; + cur = vlink(cur); + assert(cur == null || alink(cur) == prev); + } + if (prev == null) + prev = tail; + + if (valid_node(save_tail)) { + try_couple_nodes(prev, save_tail); + } + return prev; +} + + +@* Kerning. + +@c +static void add_kern_before(halfword left, halfword right) +{ + if ((!is_rightghost(right)) && + font(left) == font(right) && has_kern(font(left), character(left))) { + int k = raw_get_kern(font(left), character(left), character(right)); + if (k != 0) { + halfword kern = new_kern(k); + halfword prev = alink(right); + assert(vlink(prev) == right); + couple_nodes(prev, kern); + couple_nodes(kern, right); + } + } +} + + +static void add_kern_after(halfword left, halfword right, halfword aft) +{ + if ((!is_rightghost(right)) && + font(left) == font(right) && has_kern(font(left), character(left))) { + int k = raw_get_kern(font(left), character(left), character(right)); + if (k != 0) { + halfword kern = new_kern(k); + halfword next = vlink(aft); + assert(next == null || alink(next) == aft); + couple_nodes(aft, kern); + try_couple_nodes(kern, next); + } + } +} + + +static void +do_handle_kerning(halfword root, halfword init_left, halfword init_right) +{ + halfword cur = vlink(root); + halfword left = null; + assert(init_left == null || type(init_left) == glyph_node); + assert(init_right == null || type(init_right) == glyph_node); + if (cur == null) { + if (init_left != null && init_right != null) { + add_kern_after(init_left, init_right, root); + tlink(root) = vlink(root); + } + return; + } + if (type(cur) == glyph_node) { + set_is_glyph(cur); + if (init_left != null) + add_kern_before(init_left, cur); + left = cur; + } + while ((cur = vlink(cur)) != null) { + if (type(cur) == glyph_node) { + set_is_glyph(cur); + if (left != null) { + add_kern_before(left, cur); + if (character(left) < 0 || is_ghost(left)) { + halfword prev = alink(left); + couple_nodes(prev, cur); + flush_node(left); + } + } + left = cur; + } else { + if (type(cur) == disc_node) { + halfword right = + type(vlink(cur)) == glyph_node ? vlink(cur) : null; + do_handle_kerning(pre_break(cur), left, null); + do_handle_kerning(post_break(cur), null, right); + if (vlink_post_break(cur) != null) + tlink_post_break(cur) = tail_of_list(vlink_post_break(cur)); + do_handle_kerning(no_break(cur), left, right); + if (vlink_no_break(cur) != null) + tlink_no_break(cur) = tail_of_list(vlink_no_break(cur)); /* needed? */ + } + if (left != null) { + if (character(left) < 0 || is_ghost(left)) { + halfword prev = alink(left); + couple_nodes(prev, cur); + flush_node(left); + } + left = null; + } + } + } + if (left != null) { + if (init_right != null) + add_kern_after(left, init_right, left); + if (character(left) < 0 || is_ghost(left)) { + halfword prev = alink(left); + halfword next = vlink(left); + if (next != null) { + couple_nodes(prev, next); + tlink(root) = next; + assert(vlink(next) == null); + assert(type(next) == kern_node); + } else if (prev != root) { + vlink(prev) = null; + tlink(root) = prev; + } else { + vlink(root) = null; + tlink(root) = null; + } + flush_node(left); + } + } +} + + +halfword handle_kerning(halfword head, halfword tail) +{ + halfword save_link; + save_link = vlink(tail); + vlink(tail) = null; + tlink(head) = tail; + do_handle_kerning(head, null, null); + tail = tlink(head); + if (valid_node(save_link)) { + try_couple_nodes(tail, save_link); + } + return tail; +} + +@* ligaturing and kerning : lua-interface. + +@c +static halfword +run_lua_ligkern_callback(halfword head, halfword tail, int callback_id) +{ + lua_State *L = Luas; + if (!get_callback(L, callback_id)) { + lua_pop(L, 2); + return tail; + } + nodelist_to_lua(L, head); + nodelist_to_lua(L, tail); + if (lua_pcall(L, 2, 1, 0) != 0) { + fprintf(stdout, "error: %s\n", lua_tostring(L, -1)); + lua_pop(L, 2); + lua_error(L); + return tail; + } + tail = nodelist_from_lua(L); + if (fix_node_lists) + fix_node_list(head); + lua_pop(L, 2); + return tail; +} + + +halfword new_ligkern(halfword head, halfword tail) +{ + int callback_id = 0; + + assert(head != null); + if (vlink(head) == null) + return tail; + + callback_id = callback_defined(ligaturing_callback); + if (callback_id > 0) { + tail = run_lua_ligkern_callback(head, tail, callback_id); + if (tail == null) + tail = tail_of_list(head); + } else if (callback_id == 0) { + tail = handle_ligaturing(head, tail); + } + + callback_id = callback_defined(kerning_callback); + if (callback_id > 0) { + tail = run_lua_ligkern_callback(head, tail, callback_id); + if (tail == null) + tail = tail_of_list(head); + } else if (callback_id == 0) { + halfword nest = new_node(nesting_node, 1); + halfword cur = vlink(head); + halfword aft = vlink(tail); + couple_nodes(nest, cur); + tlink(nest) = tail; + vlink(tail) = null; + do_handle_kerning(nest, null, null); + couple_nodes(head, vlink(nest)); + tail = tlink(nest); + try_couple_nodes(tail, aft); + flush_node(nest); + } + return tail; +} |