diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/font/luafont.w')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/font/luafont.w | 4444 |
1 files changed, 2222 insertions, 2222 deletions
diff --git a/Build/source/texk/web2c/luatexdir/font/luafont.w b/Build/source/texk/web2c/luatexdir/font/luafont.w index 6ea9a4d5eea..9c7354a3f8f 100644 --- a/Build/source/texk/web2c/luatexdir/font/luafont.w +++ b/Build/source/texk/web2c/luatexdir/font/luafont.w @@ -1,2222 +1,2222 @@ -% luafont.w
-%
-% Copyright 2006-2011 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
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-#define noVERBOSE
-
-/* todo: also keys */
-
-const char *font_type_strings[] = {
- "unknown", "virtual", "real", NULL
-};
-
-const char *font_writingmode_strings[] = {
- "unknown", "horizontal", "vertical", NULL
-};
-
-const char *font_identity_strings[] = {
- "unknown", "horizontal", "vertical", 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",
- "NoLimitSubFactor",
- "NoLimitSupFactor",
- NULL,
-};
-
-/* here for now, may be useful elsewhere */
-
-int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
-
-int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) {
- const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
- int i;
- for (i=0; lst[i]; i++)
- if (strcmp(lst[i], name) == 0)
- return i;
- return -1;
-}
-
-#define dump_intfield(L,n,c) \
- lua_push_string_by_name(L,n); \
- lua_pushinteger(L, c); \
- lua_rawset(L, -3); \
-
-#define dump_stringfield(L,n,c) \
- lua_push_string_by_name(L,n); \
- lua_pushstring(L, c); \
- lua_rawset(L, -3);
-
-#define dump_booleanfield(L,n,c) \
- lua_push_string_by_name(L,n); \
- lua_pushboolean(L, c); \
- lua_rawset(L, -3);
-
-static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
-{
- int i;
- for (i = 0; i < l; i++) {
- lua_newtable(L);
- 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]);
- }
- lua_rawseti(L, -2, (i + 1));
- }
-}
-
-static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
-{
- liginfo *l;
- kerninfo *ki;
-
- lua_createtable(L, 0, 10);
-
- dump_intfield(L,width,get_charinfo_width(co));
- dump_intfield(L,height,get_charinfo_height(co));
- dump_intfield(L,depth,get_charinfo_depth(co));
-
- if (get_charinfo_italic(co) != 0) {
- dump_intfield(L,italic,get_charinfo_italic(co));
- }
- if (get_charinfo_vert_italic(co) != 0) {
- dump_intfield(L,vert_italic,get_charinfo_vert_italic(co));
- }
- if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) {
- dump_intfield(L,top_accent,get_charinfo_top_accent(co));
- }
- if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) {
- dump_intfield(L,bot_accent,get_charinfo_bot_accent(co));
- }
- if (get_charinfo_ef(co) != 1000) {
- dump_intfield(L,expansion_factor,get_charinfo_ef(co));
- }
- if (get_charinfo_lp(co) != 0) {
- dump_intfield(L,left_protruding,get_charinfo_lp(co));
- }
- if (get_charinfo_rp(co) != 0) {
- dump_intfield(L,right_protruding,get_charinfo_rp(co));
- }
- if (font_encodingbytes(f) == 2) {
- dump_intfield(L,index,get_charinfo_index(co));
- }
- if (get_charinfo_name(co) != NULL) {
- dump_stringfield(L,name,get_charinfo_name(co));
- }
- if (get_charinfo_tounicode(co) != NULL) {
- dump_stringfield(L,tounicode,get_charinfo_tounicode(co));
- }
- if (get_charinfo_tag(co) == list_tag) {
- dump_intfield(L,next,get_charinfo_remainder(co));
- }
- if (get_charinfo_used(co)) {
- dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false));
- }
- if (get_charinfo_tag(co) == ext_tag) {
- extinfo *h;
- h = get_charinfo_hor_variants(co);
- if (h != NULL) {
- int i = 1;
- lua_push_string_by_name(L,horiz_variants);
- 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_rawset(L, -3);
- }
- h = get_charinfo_vert_variants(co);
- if (h != NULL) {
- int i = 1;
- lua_push_string_by_name(L,vert_variants);
- 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_rawset(L, -3);
- }
- }
- ki = get_charinfo_kerns(co);
- if (ki != NULL) {
- int i;
- lua_push_string_by_name(L,kerns);
- lua_createtable(L, 10, 1);
- for (i = 0; !kern_end(ki[i]); i++) {
- if (kern_disabled(ki[i])) {
- /* skip like in lookup */
- } else {
- lua_rawgeti(L, -1, kern_char(ki[i]));
- if (lua_type(L,-1) == LUA_TNIL) {
- lua_pop(L,1);
- if (kern_char(ki[i]) == right_boundarychar) {
- lua_push_string_by_name(L,right_boundary);
- } else {
- lua_pushinteger(L, kern_char(ki[i]));
- }
- lua_pushinteger(L, kern_kern(ki[i]));
- lua_rawset(L, -3);
- } else {
- /* first one wins */
- lua_pop(L,1);
- }
- }
- }
- lua_rawset(L, -3);
- }
- l = get_charinfo_ligatures(co);
- if (l != NULL) {
- int i;
- lua_push_string_by_name(L,ligatures);
- lua_createtable(L, 10, 1);
- for (i = 0; !lig_end(l[i]); i++) {
- if (lig_char(l[i]) == right_boundarychar) {
- lua_push_string_by_name(L,right_boundary);
- } else {
- lua_pushinteger(L, lig_char(l[i]));
- }
- lua_createtable(L, 0, 2);
- lua_push_string_by_name(L,type);
- lua_pushinteger(L, lig_type(l[i]));
- lua_rawset(L, -3);
- lua_push_string_by_name(L,char);
- lua_pushinteger(L, lig_replacement(l[i]));
- lua_rawset(L, -3);
- lua_rawset(L, -3);
- }
- lua_rawset(L, -3);
- }
-
- lua_push_string_by_name(L,mathkern);
- lua_newtable(L);
- {
- int i, j;
- i = get_charinfo_math_kerns(co, top_right_kern);
- j = 0;
- if (i > 0) {
- j++;
- lua_push_string_by_name(L,top_right);
- lua_newtable(L);
- dump_math_kerns(L, co, i, top_right_kern);
- lua_rawset(L, -3);
- }
- i = get_charinfo_math_kerns(co, top_left_kern);
- if (i > 0) {
- j++;
- lua_push_string_by_name(L,top_left);
- lua_newtable(L);
- dump_math_kerns(L, co, i, top_left_kern);
- lua_rawset(L, -3);
- }
- i = get_charinfo_math_kerns(co, bottom_right_kern);
- if (i > 0) {
- j++;
- lua_push_string_by_name(L,bottom_right);
- lua_newtable(L);
- dump_math_kerns(L, co, i, bottom_right_kern);
- lua_rawset(L, -3);
- }
- i = get_charinfo_math_kerns(co, bottom_left_kern);
- if (i > 0) {
- j++;
- lua_push_string_by_name(L,bottom_left);
- lua_newtable(L);
- dump_math_kerns(L, co, i, bottom_left_kern);
- lua_rawset(L, -3);
- }
- if (j > 0)
- lua_rawset(L, -3);
- else
- lua_pop(L, 2);
- }
-}
-
-static void write_lua_parameters(lua_State * L, int f)
-{
- int k;
- lua_push_string_by_name(L,parameters);
- lua_newtable(L);
- for (k = 1; k <= font_params(f); k++) {
- switch (k) {
- case slant_code:
- dump_intfield(L,slant,font_param(f, k));
- break;
- case space_code:
- dump_intfield(L,space,font_param(f, k));
- break;
- case space_stretch_code:
- dump_intfield(L,space_stretch,font_param(f, k));
- break;
- case space_shrink_code:
- dump_intfield(L,space_shrink,font_param(f, k));
- break;
- case x_height_code:
- dump_intfield(L,x_height,font_param(f, k));
- break;
- case quad_code:
- dump_intfield(L,quad,font_param(f, k));
- break;
- case extra_space_code:
- dump_intfield(L,extra_space,font_param(f, k));
- break;
- default:
- lua_pushinteger(L, font_param(f, k));
- lua_rawseti(L, -2, k);
- }
- }
- lua_rawset(L, -3);
-}
-
-@ @c
-static void write_lua_math_parameters(lua_State * L, int f)
-{
- int k;
- lua_push_string_by_name(L,MathConstants);
- lua_newtable(L);
- for (k = 1; k <= font_math_params(f); k++) {
- lua_pushinteger(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_rawset(L, -3);
-}
-
-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_push_string_by_name(L,name);
- lua_pushstring(L, font_name(f));
- lua_rawset(L, -3);
- if (font_area(f) != NULL) {
- dump_stringfield(L,area,font_area(f));
- }
- if (font_filename(f) != NULL) {
- dump_stringfield(L,filename,font_filename(f));
- }
- if (font_fullname(f) != NULL) {
- dump_stringfield(L,fullname,font_fullname(f));
- }
- if (font_psname(f) != NULL) {
- dump_stringfield(L,psname,font_psname(f));
- }
- if (font_encodingname(f) != NULL) {
- dump_stringfield(L,encodingname,font_encodingname(f));
- }
-
- dump_booleanfield(L,used,(font_used(f) ? true : false));
- dump_stringfield(L,type,font_type_strings[font_type(f)]);
- dump_stringfield(L,format,font_format_strings[font_format(f)]);
- dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]);
- dump_stringfield(L,identity,font_identity_strings[font_identity(f)]);
- dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]);
-
- dump_intfield(L,units_per_em,font_units_per_em(f));
- dump_intfield(L,size,font_size(f));
- dump_intfield(L,designsize,font_dsize(f));
- dump_intfield(L,checksum,font_checksum(f));
- dump_intfield(L,slant,font_slant(f));
- dump_intfield(L,extend,font_extend(f));
- dump_intfield(L,direction,font_natural_dir(f));
- dump_intfield(L,encodingbytes,font_encodingbytes(f));
- dump_booleanfield(L,oldmath,font_oldmath(f));
- dump_intfield(L,tounicode,font_tounicode(f));
-
- /* the next one is read only */
- if (font_max_shrink(f) != 0) {
- dump_intfield(L,shrink,font_max_shrink(f));
- }
- if (font_max_stretch(f) != 0) {
- dump_intfield(L,stretch,font_max_stretch(f));
- }
- if (font_step(f) != 0) {
- dump_intfield(L,step,font_step(f));
- }
- if (font_auto_expand(f) != 0) {
- dump_booleanfield(L,auto_expand,font_auto_expand(f));
- }
- if (pdf_font_attr(f) != 0) {
- char *s = makecstring(pdf_font_attr(f));
- dump_stringfield(L,attributes,s);
- free(s);
- }
-
- /* params */
- write_lua_parameters(L, f);
- write_lua_math_parameters(L, f);
-
- /* chars */
- lua_push_string_by_name(L,characters);
- lua_createtable(L, font_tables[f]->charinfo_size, 0); /* all characters */
- if (has_left_boundary(f)) {
- co = get_charinfo(f, left_boundarychar);
- lua_push_string_by_name(L,left_boundary);
- font_char_to_lua(L, f, co);
- lua_rawset(L, -3);
- }
- if (has_right_boundary(f)) {
- co = get_charinfo(f, right_boundarychar);
- lua_push_string_by_name(L,right_boundary);
- font_char_to_lua(L, f, co);
- lua_rawset(L, -3);
- }
- for (k = font_bc(f); k <= font_ec(f); k++) {
- if (quick_char_exists(f, k)) {
- lua_pushinteger(L, k);
- co = get_charinfo(f, k);
- font_char_to_lua(L, f, co);
- lua_rawset(L, -3);
- }
- }
- lua_rawset(L, -3);
-
- 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;
-}
-
-#define count_hash_items(L,name,n) \
- n = 0; \
- lua_key_rawgeti(name); \
- if (lua_type(L, -1) == LUA_TTABLE) { \
- lua_pushnil(L); \
- while (lua_next(L, -2) != 0) { \
- n++; \
- lua_pop(L, 1); \
- } \
- } \
- if (n) { \
- /* keep table on stack */ \
- } else{ \
- lua_pop(L, 1); \
- }
-
-@ @c
-#define streq(a,b) (strcmp(a,b)==0)
-
-#define append_packet(k) { *(cp++) = (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)); \
-}
-
-@ @c
-static void append_float(eight_bits ** cpp, float a)
-{
- unsigned int i;
- eight_bits *cp = *cpp;
- union U {
- float a;
- eight_bits b[sizeof(float)];
- } u;
- u.a = a;
- for (i = 0; i < sizeof(float); i++)
- append_packet(u.b[i]);
- *cpp = cp;
-}
-
-static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values)
-{
- int k, t;
- const char *s;
- int i = dflt;
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- t = lua_type(L,-1);
- if (t == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -1);
- } else if (t == LUA_TSTRING) {
- 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 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 *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
-{
- char *i;
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- if (lua_type(L,-1) == LUA_TSTRING) {
- i = xstrdup(lua_tostring(L, -1));
- } else if (dflt == NULL) {
- i = NULL;
- } else {
- i = xstrdup(dflt);
- }
- lua_pop(L, 1);
- return i;
-}
-
-static const char *n_string_field(lua_State * L, int name_index)
-{
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- return lua_tostring(L,-1);
-}
-
-static int n_some_field(lua_State * L, int name_index)
-{
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- return lua_type(L,-1);
-}
-
-/*static void init_font_string_pointers(lua_State * L){}*/
-
-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_rawlen(L, -1); i++) {
- lua_rawgeti(L, -1, i);
- if (lua_istable(L, -1)) {
- lua_rawgeti(L, -1, 1);
- if (lua_type(L,-1) == LUA_TSTRING) {
- const char *s = lua_tostring(L, -1);
- if (lua_key_eq(s, font)) {
- l += 5;
- ff = 1;
- } else if (lua_key_eq(s, char)) {
- if (ff == 0) {
- l += 5;
- }
- l += 5;
- ff = 1;
- } else if (lua_key_eq(s, slot)) {
- l += 10;
- ff = 1;
- } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
- ;
- } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
- l++;
- } else if (lua_key_eq(s, rule)) {
- l += 9;
- } else if (lua_key_eq(s, right) || lua_key_eq(s, node)
- || lua_key_eq(s, down) || lua_key_eq(s, image)) {
- l += 5;
- } else if (lua_key_eq(s, scale)) {
- l += sizeof(float) + 1;
- } else if (lua_key_eq(s, special) || lua_key_eq(s, lua)) {
- size_t len;
- lua_rawgeti(L, -2, 2);
- if (lua_type(L,-1) == LUA_TSTRING) {
- (void) lua_tolstring(L, -1, &len);
- lua_pop(L, 1);
- if (len > 0) {
- l = (int) (l + 5 + (int) len);
- }
- } else {
- lua_pop(L, 1);
- normal_error("vf command","invalid packet special");
- /* fprintf(stdout, "invalid packet special!\n"); */
- }
- } else {
- normal_error("vf command","unknown packet command");
- /* fprintf(stdout, "unknown packet command %s!\n", s); */
- }
- } else {
- normal_error("vf command","no packet command");
- /* fprintf(stdout, "no packet command!\n"); */
- }
- lua_pop(L, 1); /* command name */
- }
- lua_pop(L, 1); /* item */
- }
- return l;
-}
-
-static 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, internal_font_number f, int atsize)
-{
- int i, n, m;
- size_t l;
- int cmd;
- const char *s;
- eight_bits *cpackets, *cp;
- int ff = 0;
- int max_f = 0;
- int pc = count_char_packet_bytes(L);
- if (pc <= 0)
- return;
- while (l_fonts[(max_f + 1)] != 0)
- max_f++;
- cp = cpackets = xmalloc((unsigned) (pc + 1));
- for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
- lua_rawgeti(L, -1, i);
- if (lua_istable(L, -1)) {
- /* fetch the command code */
- lua_rawgeti(L, -1, 1);
- if (lua_type(L,-1) == LUA_TSTRING) {
- s = lua_tostring(L, -1);
- cmd = 0;
- if (lua_key_eq(s, font)) {
- cmd = packet_font_code;
- } else if (lua_key_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 (lua_key_eq(s, slot)) {
- cmd = packet_nop_code;
- lua_rawgeti(L, -2, 2);
- n = (int) luaL_checkinteger(L, -1);
- if (n ==0) {
- ff = f;
- } else {
- ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
- }
- lua_rawgeti(L, -3, 3);
- n = (int) luaL_checkinteger(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 (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
- cmd = packet_nop_code;
- } else if (lua_key_eq(s, node)) {
- cmd = packet_node_code;
- } else if (lua_key_eq(s, push)) {
- cmd = packet_push_code;
- } else if (lua_key_eq(s, pop)) {
- cmd = packet_pop_code;
- } else if (lua_key_eq(s, rule)) {
- cmd = packet_rule_code;
- } else if (lua_key_eq(s, right)) {
- cmd = packet_right_code;
- } else if (lua_key_eq(s, down)) {
- cmd = packet_down_code;
- } else if (lua_key_eq(s, special)) {
- cmd = packet_special_code;
- } else if (lua_key_eq(s, image)) {
- cmd = packet_image_code;
- } else if (lua_key_eq(s, scale)) {
- cmd = packet_scale_code;
- } else if (lua_key_eq(s, lua)) {
- cmd = packet_lua_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) luaL_checkinteger(L, -1);
- if (n == 0) {
- ff = n;
- } else {
- 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) luaL_checkinteger(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) luaL_checkinteger(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) luaL_checkinteger(L, -1);
- do_store_four(sp_to_dvi(n, atsize));
- lua_rawgeti(L, -3, 3);
- n = (int) luaL_checkinteger(L, -1);
- do_store_four(sp_to_dvi(n, atsize));
- lua_pop(L, 2);
- break;
- case packet_special_code:
- case packet_lua_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- s = luaL_checklstring(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_REGISTRYINDEX); /* ... */
- do_store_four(n);
- break;
- case packet_nop_code:
- break;
- case packet_scale_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- append_float(&cp, (float) luaL_checknumber(L, -1));
- lua_pop(L, 1);
- break;
- default:
- normal_error("vf command","invalid packet code");
- /* fprintf(stdout, "Unknown char packet code %s\n", s); */
- }
- }
- lua_pop(L, 1); /* command code */
- } else {
- normal_error("vf command","commands has to be a tbale");
- /* fprintf(stdout, "Found a `commands' item that is not a table\n"); */
- }
- 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");*/
- lua_key_rawgeti(cidinfo);
- if (lua_istable(L, -1)) {
- i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
- set_font_cidversion(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
- set_font_cidsupplement(f, i);
- s = n_string_field_copy(L, lua_key_index(registry), "Adobe"); /* Adobe-Identity-0 */
- set_font_cidregistry(f, s);
- s = n_string_field_copy(L, lua_key_index(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, t;
- const char *s;
- /*lua_getfield(L, -1, "parameters");*/
- lua_key_rawgeti(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_type(L, -2) == LUA_TNUMBER) {
- i = (int) lua_tointeger(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_type(L, -1) == LUA_TNUMBER) {
- n = lua_roundnumber(L, -1); /* round ? */
- set_font_param(f, i, n);
- }
- lua_pop(L, 1);
- }
- lua_pushnil(L); /* first key */
- while (lua_next(L, -2) != 0) {
- t = lua_type(L,-2);
- if (t == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -2);
- if (i >= 8) {
- if (lua_type(L,-1) == LUA_TNUMBER) {
- n = lua_roundnumber(L, -1);
- } else {
- n = 0;
- }
- set_font_param(f, i, n);
- }
- } else if (t == LUA_TSTRING) {
- s = lua_tostring(L, -2);
- if (lua_type(L,-1) == LUA_TNUMBER) {
- n = lua_roundnumber(L, -1);
- } else {
- n = 0;
- }
- if (lua_key_eq(s, slant)) {
- set_font_param(f, slant_code, n);
- } else if (lua_key_eq(s, space)) {
- set_font_param(f, space_code, n);
- } else if (lua_key_eq(s, space_stretch)) {
- set_font_param(f, space_stretch_code, n);
- } else if (lua_key_eq(s, space_shrink)) {
- set_font_param(f, space_shrink_code, n);
- } else if (lua_key_eq(s, x_height)) {
- set_font_param(f, x_height_code, n);
- } else if (lua_key_eq(s, quad)) {
- set_font_param(f, quad_code, n);
- } else if (lua_key_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, t;
- /*lua_getfield(L, -1, "MathConstants");*/
- lua_key_rawgeti(MathConstants);
- if (lua_istable(L, -1)) {
- lua_pushnil(L);
- while (lua_next(L, -2) != 0) {
- t = lua_type(L,-2);
- if (t == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -2);
- } else if (t == LUA_TSTRING) {
- i = ff_checkoption(L, -2, NULL, MATH_param_names);
- }
- n = (int) lua_roundnumber(L, -1);
- if (i > 0) {
- set_font_math_param(f, i, n);
- }
- lua_pop(L, 1); /* pop value */
- }
- set_font_oldmath(f,false);
- } else {
- set_font_oldmath(f,true);
- }
- lua_pop(L, 1);
-}
-
-@ @c
-#define MIN_INF -0x7FFFFFFF
-
-static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
-{
- int l, k;
- scaled ht, krn;
- lua_key_direct_rawgeti(index);
- if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
- for (l = 0; l < k; l++) {
- lua_rawgeti(L, -1, (l + 1));
- if (lua_istable(L, -1)) {
- ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
- krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
- if (krn > MIN_INF && ht > MIN_INF)
- add_charinfo_math_kern(co, id, ht, krn);
- }
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
-}
-
-@ @c
-static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math)
-{
- int k, r, t, lt, u, n;
- 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 = lua_numeric_field_by_index(L, lua_key_index(width), 0);
- set_charinfo_width(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
- set_charinfo_height(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
- set_charinfo_depth(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
- set_charinfo_italic(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0);
- set_charinfo_vert_italic(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
- set_charinfo_index(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000);
- set_charinfo_ef(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
- set_charinfo_lp(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
- set_charinfo_rp(co, j);
- k = n_boolean_field(L, lua_key_index(used), 0);
- set_charinfo_used(co, k);
- s = n_string_field(L, lua_key_index(name));
- if (s != NULL)
- set_charinfo_name(co, xstrdup(s));
- else
- set_charinfo_name(co, NULL);
- /* n_string_field leaves a value on stack*/
- lua_pop(L,1);
- u = n_some_field(L,lua_key_index(tounicode));
- if (u == LUA_TNUMBER) {
- u = lua_tointeger(L,-1);
- if (u < 0) {
- set_charinfo_tounicode(co, NULL);
- } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
- char *s = malloc(5);
- sprintf(s,"%04X",(unsigned int) u);
- set_charinfo_tounicode(co,s);
- } else {
- char *s = malloc(9);
- u = u - 0x10000;
- sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
- set_charinfo_tounicode(co,s);
- }
- } else if (u == LUA_TTABLE) {
- n = lua_rawlen(L,-1);
- u = 0;
- for (k = 1; k <= n; k++) {
- lua_rawgeti(L, -1, k);
- if (lua_type(L,-1) == LUA_TNUMBER) {
- u = lua_tointeger(L,-1);
- } else {
- lua_pop(L, 1);
- break;
- }
- if (u < 0) {
- u = -1;
- lua_pop(L, 1);
- break;
- } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
- u = u + 4;
- } else {
- u = u + 8;
- }
- lua_pop(L, 1);
- }
- if (u>0) {
- char *s = malloc(u+1);
- char *t = s ;
- for (k = 1; k <= n; k++) {
- lua_rawgeti(L, -1, k);
- u = lua_tointeger(L,-1);
- if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
- sprintf(t,"%04X",(unsigned int) u);
- t += 4;
- } else {
- u = u - 0x10000;
- sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
- t += 8;
- }
- lua_pop(L, 1);
- }
- set_charinfo_tounicode(co,s);
- } else {
- set_charinfo_tounicode(co, NULL);
- }
- } else if (u == LUA_TSTRING) {
- s = lua_tostring(L,-1);
- set_charinfo_tounicode(co, xstrdup(s));
- } else {
- set_charinfo_tounicode(co, NULL);
- }
- /* ... leaves a value on stack*/
- lua_pop(L,1);
-
- if (has_math) {
- j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
- set_charinfo_top_accent(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
- set_charinfo_bot_accent(co, j);
- k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
- if (k >= 0) {
- set_charinfo_tag(co, list_tag);
- set_charinfo_remainder(co, k);
- }
-
- lua_key_rawgeti(extensible);
- if (lua_istable(L, -1)) {
- int top, bot, mid, rep;
- top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
- bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
- mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
- rep = lua_numeric_field_by_index(L, lua_key_index(rep), 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 {
- formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field",
- font_name(f), (int) i);
- }
- }
- lua_pop(L, 1);
-
- lua_key_rawgeti(horiz_variants);
- 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 = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
- extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
- startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
- endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
- advance = lua_numeric_field_by_index(L, lua_key_index(advance), 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_key_rawgeti(vert_variants);
- 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 = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
- extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
- startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
- endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
- advance = lua_numeric_field_by_index(L, lua_key_index(advance), 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_key_rawgeti(mathkern);
- if (lua_istable(L, -1)) {
- store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
- store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
- store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
- store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
- }
- lua_pop(L, 1);
- }
- /* end of |has_math| */
- count_hash_items(L, kerns, nk);
- if (nk > 0) {
- /* kerns table still on stack */
- ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
- ctr = 0;
- lua_pushnil(L); /* traverse hash */
- while (lua_next(L, -2) != 0) {
- k = non_boundarychar;
- lt = lua_type(L,-2);
- if (lt == LUA_TNUMBER) {
- k = (int) lua_tointeger(L, -2); /* adjacent char */
- if (k < 0)
- k = non_boundarychar;
- } else if (lt == LUA_TSTRING) {
- s = lua_tostring(L, -2);
- if (lua_key_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 {
- formatted_warning("font", "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 {
- formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field",
- font_name(f), (int) i);
- }
- lua_pop(L, 1);
- }
-
- /* packet commands */
- lua_key_rawgeti(commands);
- 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, f, atsize);
- }
- }
- lua_pop(L, 1);
-
- /* ligatures */
- count_hash_items(L, ligatures, nl);
- if (nl > 0) {
- /* ligatures table still on stack */
- cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
- ctr = 0;
- lua_pushnil(L); /* traverse hash */
- while (lua_next(L, -2) != 0) {
- k = non_boundarychar;
- lt = lua_type(L,-2);
- if (lt == LUA_TNUMBER) {
- k = (int) lua_tointeger(L, -2); /* adjacent char */
- if (k < 0) {
- k = non_boundarychar;
- }
- } else if (lt == LUA_TSTRING) {
- s = lua_tostring(L, -2);
- if (lua_key_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 = lua_numeric_field_by_index(L, lua_key_index(char), -1); /* ligature */
- }
- if (r != -1 && k != non_boundarychar) {
- t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
- set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r);
- ctr++;
- } else {
- formatted_warning("font", "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 {
- formatted_warning("font", "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, lt;
- 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 ;
- boolean no_math = false;
-
- /* will we save a cache of the luat table? */
-
- save_ref = 1; /* we start with ss = "yes" */
- ss = NULL;
- ss = n_string_field(L, lua_key_index(cache));
- if (lua_key_eq(ss, no))
- save_ref = -1;
- else if (lua_key_eq(ss, renew))
- save_ref = 0;
- /* n_string_field leaves a value on stack*/
- lua_pop(L,1);
-
- /* the table is at stack index -1 */
-
- s = n_string_field_copy(L,lua_key_index(area), "");
- set_font_area(f, s);
- s = n_string_field_copy(L, lua_key_index(filename), NULL);
- set_font_filename(f, s);
- s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
- set_font_encodingname(f, s);
-
- s = n_string_field_copy(L, lua_key_index(name), NULL);
- set_font_name(f, s);
- s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
- set_font_fullname(f, s);
-
- if (s == NULL) {
- formatted_error("font","lua-loaded font '%d' has no name!", f);
- return false;
- }
- s = n_string_field_copy(L, lua_key_index(psname), NULL);
- set_font_psname(f, s);
-
- i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
- set_font_units_per_em(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
- set_font_dsize(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
- set_font_size(f, i);
- set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
- i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
- set_font_natural_dir(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
- set_font_encodingbytes(f, (char) i);
- i = n_boolean_field(L,lua_key_index(oldmath), 0);
- set_font_oldmath(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
- set_font_tounicode(f, (char) i);
-
- i = lua_numeric_field_by_index(L,lua_key_index(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 = lua_numeric_field_by_index(L,lua_key_index(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 = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par);
- set_hyphen_char(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par);
- set_skew_char(f, i);
- i = n_boolean_field(L, lua_key_index(used), 0);
- set_font_used(f, (char) i);
-
- s = n_string_field_copy(L, lua_key_index(attributes), NULL);
- if (s != NULL && strlen(s) > 0) {
- i = maketexstring(s);
- set_pdf_font_attr(f, i);
- }
- free(s);
-
- i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
- set_font_type(f, i);
- i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
- set_font_format(f, i);
- i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings);
- set_font_writingmode(f, i);
- i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings);
- set_font_identity(f, i);
- i = n_enum_field(L, lua_key_index(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 */
- count_hash_items(L, fonts, n);
- if (n > 0) {
- /* font table still on stack */
- l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
- memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
- for (i = 1; i <= n; i++) {
- lua_rawgeti(L, -1, i);
- if (lua_istable(L, -1)) {
- lua_key_rawgeti(id);
- if (lua_isnumber(L, -1)) {
- l_fonts[i] = (int) lua_tointeger(L, -1);
- if (l_fonts[i] == 0) {
- l_fonts[i] = (int) f;
- }
- lua_pop(L, 2); /* pop id and entry */
- continue;
- }
- lua_pop(L, 1); /* pop id */
- };
- ss = NULL;
- if (lua_istable(L, -1)) {
- ss = n_string_field(L, lua_key_index(name));
- /* string is anchored */
- lua_pop(L,1);
- }
- if (ss != NULL) {
- t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
- /* 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 {
- formatted_error("font","invalid local font in lua-loaded font '%s'", font_name(f));
- }
- lua_pop(L, 1); /* pop list entry */
- }
- lua_pop(L, 1); /* pop font table */
- } else if (font_type(f) == virtual_font_type) {
- formatted_error("font","invalid local fonts in lua-loaded font '%s'", 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 = n_boolean_field(L, lua_key_index(nomath), 0);
- read_lua_parameters(L, f);
- if (!no_math) {
- read_lua_math_parameters(L, f);
- if (n_boolean_field(L, lua_key_index(oldmath), 0)) {
- set_font_oldmath(f,true);
- }
-
- } else {
- set_font_oldmath(f,true);
- }
- read_lua_cidinfo(L, f);
-
- /* characters */
- lua_key_rawgeti(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) {
- 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) {
- lt = lua_type(L,-2);
- if (lt == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -2);
- if (i >= 0) {
- font_char_from_lua(L, f, i, l_fonts, !no_math);
- }
- } else if (lt == LUA_TSTRING) {
- const char *ss1 = lua_tostring(L, -2);
- if (lua_key_eq(ss1, left_boundary)) {
- font_char_from_lua(L, f, left_boundarychar, l_fonts,
- !no_math);
- } else if (lua_key_eq(ss1, 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 = lua_numeric_field_by_index(L, lua_key_index(step), 0);
- if (fstep < 0)
- fstep = 0;
- if (fstep > 100)
- fstep = 100;
- if (fstep != 0) {
- int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
- int fstretch =lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
- int fexpand = n_boolean_field(L, lua_key_index(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);
- }
- }
-
- } else {
- /* jikes, no characters */
- formatted_warning("font","lua-loaded font '%d' with name '%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 */
- formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f));
- }
- if (l_fonts != NULL)
- free(l_fonts);
- return true;
-}
-
-@* Ligaturing.
-
-@c
-static void nesting_append(halfword nest1, halfword newn)
-{
- halfword tail = tlink(nest1);
- if (tail == null) {
- couple_nodes(nest1, newn);
- } else {
- couple_nodes(tail, newn);
- }
- tlink(nest1) = newn;
-}
-
-static void nesting_prepend(halfword nest1, halfword newn)
-{
- halfword head = vlink(nest1);
- couple_nodes(nest1, newn);
- if (head == null) {
- tlink(nest1) = newn;
- } else {
- couple_nodes(newn, head);
- }
-}
-
-static void nesting_prepend_list(halfword nest1, halfword newn)
-{
- halfword head = vlink(nest1);
- couple_nodes(nest1, newn);
- if (head == null) {
- tlink(nest1) = tail_of_list(newn);
- } else {
- halfword tail = tail_of_list(newn);
- couple_nodes(tail, head);
- }
-}
-
-static int test_ligature(liginfo * lig, halfword left, halfword right)
-{
- if (type(left) != glyph_node)
- return 0;
- 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;
- 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);
- }
- tlink(root) = cur;
- return root;
-}
-
-static halfword handle_lig_word(halfword cur)
-{
- halfword right = null;
- if (type(cur) == 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;
- }
- 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;
- /* 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);
- 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);
- 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) == 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) {
- /* 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);
- 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'
- */
- /* is it tail necessary ? */
- halfword last1 = vlink(next), tail ;
- uncouple_node(next);
- try_couple_nodes(fwd, last1);
- /* \.{{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 */
- return cur;
- }
- /* step-to-next-node */
- /* \.{--\\par} allows |vlink(cur)| to be null */
- cur = vlink(cur);
- }
-
- return cur;
-}
-
-@ Return value is the new tail, head should be a dummy
-
-@c
-halfword handle_ligaturing(halfword head, halfword tail)
-{
- halfword save_tail1 = null; /* trick to allow explicit |node==null| tests */
- halfword cur, prev;
-
- if (vlink(head) == null)
- return tail;
- if (tail != null) {
- save_tail1 = 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) == boundary_node)) {
- cur = handle_lig_word(cur);
- }
- prev = cur;
- cur = vlink(cur);
- }
- if (prev == null) {
- /* hh: looks bad to me */
- prev = tail;
- }
-
- if (tail != null) {
- try_couple_nodes(prev, save_tail1);
- }
- 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);
- couple_nodes(prev, kern);
- couple_nodes(kern, right);
- /* update the attribute list (inherit from left) */
- delete_attribute_ref(node_attr(kern));
- add_node_attr_ref(node_attr(left));
- node_attr(kern) = node_attr(left);
- }
- }
-}
-
-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);
- couple_nodes(aft, kern);
- try_couple_nodes(kern, next);
- /* update the attribute list (inherit from left == aft) */
- delete_attribute_ref(node_attr(kern));
- add_node_attr_ref(node_attr(aft));
- node_attr(kern) = node_attr(aft);
- }
- }
-}
-
-static void do_handle_kerning(halfword root, halfword init_left, halfword init_right)
-{
- halfword cur = vlink(root);
- halfword left = null;
- 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);
- if (vlink_pre_break(cur) != null)
- tlink_pre_break(cur) = tail_of_list(vlink_pre_break(cur));
- 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;
- } 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;
-}
-*/
-
-halfword handle_kerning(halfword head, halfword tail)
-{
- halfword save_link = null;
- if (tail == null) {
- tlink(head) = null;
- do_handle_kerning(head, null, null);
- } else {
- 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)
-{
- int i;
- int top = lua_gettop(Luas);
- if (!get_callback(Luas, callback_id)) {
- lua_pop(Luas, 2);
- return tail;
- }
- nodelist_to_lua(Luas, head);
- nodelist_to_lua(Luas, tail);
- if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) {
- luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
- return tail;
- }
- fix_node_list(head);
- lua_settop(Luas, top);
- return tail;
-}
-
-halfword new_ligkern(halfword head, halfword tail)
-{
- int callback_id = 0;
- 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 nest1 = new_node(nesting_node, 1);
- halfword cur = vlink(head);
- halfword aft = vlink(tail);
- couple_nodes(nest1, cur);
- tlink(nest1) = tail;
- vlink(tail) = null;
- do_handle_kerning(nest1, null, null);
- couple_nodes(head, vlink(nest1));
- tail = tlink(nest1);
- try_couple_nodes(tail, aft);
- flush_node(nest1);
- }
- return tail;
-}
+% luafont.w +% +% Copyright 2006-2011 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 +#include "ptexlib.h" +#include "lua/luatex-api.h" + +#define noVERBOSE + +/* todo: also keys */ + +const char *font_type_strings[] = { + "unknown", "virtual", "real", NULL +}; + +const char *font_writingmode_strings[] = { + "unknown", "horizontal", "vertical", NULL +}; + +const char *font_identity_strings[] = { + "unknown", "horizontal", "vertical", 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", + "NoLimitSubFactor", + "NoLimitSupFactor", + NULL, +}; + +/* here for now, may be useful elsewhere */ + +int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]); + +int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return -1; +} + +#define dump_intfield(L,n,c) \ + lua_push_string_by_name(L,n); \ + lua_pushinteger(L, c); \ + lua_rawset(L, -3); \ + +#define dump_stringfield(L,n,c) \ + lua_push_string_by_name(L,n); \ + lua_pushstring(L, c); \ + lua_rawset(L, -3); + +#define dump_booleanfield(L,n,c) \ + lua_push_string_by_name(L,n); \ + lua_pushboolean(L, c); \ + lua_rawset(L, -3); + +static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id) +{ + int i; + for (i = 0; i < l; i++) { + lua_newtable(L); + 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]); + } + lua_rawseti(L, -2, (i + 1)); + } +} + +static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co) +{ + liginfo *l; + kerninfo *ki; + + lua_createtable(L, 0, 10); + + dump_intfield(L,width,get_charinfo_width(co)); + dump_intfield(L,height,get_charinfo_height(co)); + dump_intfield(L,depth,get_charinfo_depth(co)); + + if (get_charinfo_italic(co) != 0) { + dump_intfield(L,italic,get_charinfo_italic(co)); + } + if (get_charinfo_vert_italic(co) != 0) { + dump_intfield(L,vert_italic,get_charinfo_vert_italic(co)); + } + if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) { + dump_intfield(L,top_accent,get_charinfo_top_accent(co)); + } + if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) { + dump_intfield(L,bot_accent,get_charinfo_bot_accent(co)); + } + if (get_charinfo_ef(co) != 1000) { + dump_intfield(L,expansion_factor,get_charinfo_ef(co)); + } + if (get_charinfo_lp(co) != 0) { + dump_intfield(L,left_protruding,get_charinfo_lp(co)); + } + if (get_charinfo_rp(co) != 0) { + dump_intfield(L,right_protruding,get_charinfo_rp(co)); + } + if (font_encodingbytes(f) == 2) { + dump_intfield(L,index,get_charinfo_index(co)); + } + if (get_charinfo_name(co) != NULL) { + dump_stringfield(L,name,get_charinfo_name(co)); + } + if (get_charinfo_tounicode(co) != NULL) { + dump_stringfield(L,tounicode,get_charinfo_tounicode(co)); + } + if (get_charinfo_tag(co) == list_tag) { + dump_intfield(L,next,get_charinfo_remainder(co)); + } + if (get_charinfo_used(co)) { + dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false)); + } + if (get_charinfo_tag(co) == ext_tag) { + extinfo *h; + h = get_charinfo_hor_variants(co); + if (h != NULL) { + int i = 1; + lua_push_string_by_name(L,horiz_variants); + 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_rawset(L, -3); + } + h = get_charinfo_vert_variants(co); + if (h != NULL) { + int i = 1; + lua_push_string_by_name(L,vert_variants); + 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_rawset(L, -3); + } + } + ki = get_charinfo_kerns(co); + if (ki != NULL) { + int i; + lua_push_string_by_name(L,kerns); + lua_createtable(L, 10, 1); + for (i = 0; !kern_end(ki[i]); i++) { + if (kern_disabled(ki[i])) { + /* skip like in lookup */ + } else { + lua_rawgeti(L, -1, kern_char(ki[i])); + if (lua_type(L,-1) == LUA_TNIL) { + lua_pop(L,1); + if (kern_char(ki[i]) == right_boundarychar) { + lua_push_string_by_name(L,right_boundary); + } else { + lua_pushinteger(L, kern_char(ki[i])); + } + lua_pushinteger(L, kern_kern(ki[i])); + lua_rawset(L, -3); + } else { + /* first one wins */ + lua_pop(L,1); + } + } + } + lua_rawset(L, -3); + } + l = get_charinfo_ligatures(co); + if (l != NULL) { + int i; + lua_push_string_by_name(L,ligatures); + lua_createtable(L, 10, 1); + for (i = 0; !lig_end(l[i]); i++) { + if (lig_char(l[i]) == right_boundarychar) { + lua_push_string_by_name(L,right_boundary); + } else { + lua_pushinteger(L, lig_char(l[i])); + } + lua_createtable(L, 0, 2); + lua_push_string_by_name(L,type); + lua_pushinteger(L, lig_type(l[i])); + lua_rawset(L, -3); + lua_push_string_by_name(L,char); + lua_pushinteger(L, lig_replacement(l[i])); + lua_rawset(L, -3); + lua_rawset(L, -3); + } + lua_rawset(L, -3); + } + + lua_push_string_by_name(L,mathkern); + lua_newtable(L); + { + int i, j; + i = get_charinfo_math_kerns(co, top_right_kern); + j = 0; + if (i > 0) { + j++; + lua_push_string_by_name(L,top_right); + lua_newtable(L); + dump_math_kerns(L, co, i, top_right_kern); + lua_rawset(L, -3); + } + i = get_charinfo_math_kerns(co, top_left_kern); + if (i > 0) { + j++; + lua_push_string_by_name(L,top_left); + lua_newtable(L); + dump_math_kerns(L, co, i, top_left_kern); + lua_rawset(L, -3); + } + i = get_charinfo_math_kerns(co, bottom_right_kern); + if (i > 0) { + j++; + lua_push_string_by_name(L,bottom_right); + lua_newtable(L); + dump_math_kerns(L, co, i, bottom_right_kern); + lua_rawset(L, -3); + } + i = get_charinfo_math_kerns(co, bottom_left_kern); + if (i > 0) { + j++; + lua_push_string_by_name(L,bottom_left); + lua_newtable(L); + dump_math_kerns(L, co, i, bottom_left_kern); + lua_rawset(L, -3); + } + if (j > 0) + lua_rawset(L, -3); + else + lua_pop(L, 2); + } +} + +static void write_lua_parameters(lua_State * L, int f) +{ + int k; + lua_push_string_by_name(L,parameters); + lua_newtable(L); + for (k = 1; k <= font_params(f); k++) { + switch (k) { + case slant_code: + dump_intfield(L,slant,font_param(f, k)); + break; + case space_code: + dump_intfield(L,space,font_param(f, k)); + break; + case space_stretch_code: + dump_intfield(L,space_stretch,font_param(f, k)); + break; + case space_shrink_code: + dump_intfield(L,space_shrink,font_param(f, k)); + break; + case x_height_code: + dump_intfield(L,x_height,font_param(f, k)); + break; + case quad_code: + dump_intfield(L,quad,font_param(f, k)); + break; + case extra_space_code: + dump_intfield(L,extra_space,font_param(f, k)); + break; + default: + lua_pushinteger(L, font_param(f, k)); + lua_rawseti(L, -2, k); + } + } + lua_rawset(L, -3); +} + +@ @c +static void write_lua_math_parameters(lua_State * L, int f) +{ + int k; + lua_push_string_by_name(L,MathConstants); + lua_newtable(L); + for (k = 1; k <= font_math_params(f); k++) { + lua_pushinteger(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_rawset(L, -3); +} + +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_push_string_by_name(L,name); + lua_pushstring(L, font_name(f)); + lua_rawset(L, -3); + if (font_area(f) != NULL) { + dump_stringfield(L,area,font_area(f)); + } + if (font_filename(f) != NULL) { + dump_stringfield(L,filename,font_filename(f)); + } + if (font_fullname(f) != NULL) { + dump_stringfield(L,fullname,font_fullname(f)); + } + if (font_psname(f) != NULL) { + dump_stringfield(L,psname,font_psname(f)); + } + if (font_encodingname(f) != NULL) { + dump_stringfield(L,encodingname,font_encodingname(f)); + } + + dump_booleanfield(L,used,(font_used(f) ? true : false)); + dump_stringfield(L,type,font_type_strings[font_type(f)]); + dump_stringfield(L,format,font_format_strings[font_format(f)]); + dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]); + dump_stringfield(L,identity,font_identity_strings[font_identity(f)]); + dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]); + + dump_intfield(L,units_per_em,font_units_per_em(f)); + dump_intfield(L,size,font_size(f)); + dump_intfield(L,designsize,font_dsize(f)); + dump_intfield(L,checksum,font_checksum(f)); + dump_intfield(L,slant,font_slant(f)); + dump_intfield(L,extend,font_extend(f)); + dump_intfield(L,direction,font_natural_dir(f)); + dump_intfield(L,encodingbytes,font_encodingbytes(f)); + dump_booleanfield(L,oldmath,font_oldmath(f)); + dump_intfield(L,tounicode,font_tounicode(f)); + + /* the next one is read only */ + if (font_max_shrink(f) != 0) { + dump_intfield(L,shrink,font_max_shrink(f)); + } + if (font_max_stretch(f) != 0) { + dump_intfield(L,stretch,font_max_stretch(f)); + } + if (font_step(f) != 0) { + dump_intfield(L,step,font_step(f)); + } + if (font_auto_expand(f) != 0) { + dump_booleanfield(L,auto_expand,font_auto_expand(f)); + } + if (pdf_font_attr(f) != 0) { + char *s = makecstring(pdf_font_attr(f)); + dump_stringfield(L,attributes,s); + free(s); + } + + /* params */ + write_lua_parameters(L, f); + write_lua_math_parameters(L, f); + + /* chars */ + lua_push_string_by_name(L,characters); + lua_createtable(L, font_tables[f]->charinfo_size, 0); /* all characters */ + if (has_left_boundary(f)) { + co = get_charinfo(f, left_boundarychar); + lua_push_string_by_name(L,left_boundary); + font_char_to_lua(L, f, co); + lua_rawset(L, -3); + } + if (has_right_boundary(f)) { + co = get_charinfo(f, right_boundarychar); + lua_push_string_by_name(L,right_boundary); + font_char_to_lua(L, f, co); + lua_rawset(L, -3); + } + for (k = font_bc(f); k <= font_ec(f); k++) { + if (quick_char_exists(f, k)) { + lua_pushinteger(L, k); + co = get_charinfo(f, k); + font_char_to_lua(L, f, co); + lua_rawset(L, -3); + } + } + lua_rawset(L, -3); + + 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; +} + +#define count_hash_items(L,name,n) \ + n = 0; \ + lua_key_rawgeti(name); \ + if (lua_type(L, -1) == LUA_TTABLE) { \ + lua_pushnil(L); \ + while (lua_next(L, -2) != 0) { \ + n++; \ + lua_pop(L, 1); \ + } \ + } \ + if (n) { \ + /* keep table on stack */ \ + } else{ \ + lua_pop(L, 1); \ + } + +@ @c +#define streq(a,b) (strcmp(a,b)==0) + +#define append_packet(k) { *(cp++) = (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)); \ +} + +@ @c +static void append_float(eight_bits ** cpp, float a) +{ + unsigned int i; + eight_bits *cp = *cpp; + union U { + float a; + eight_bits b[sizeof(float)]; + } u; + u.a = a; + for (i = 0; i < sizeof(float); i++) + append_packet(u.b[i]); + *cpp = cp; +} + +static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values) +{ + int k, t; + const char *s; + int i = dflt; + lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L, -2); + t = lua_type(L,-1); + if (t == LUA_TNUMBER) { + i = (int) lua_tointeger(L, -1); + } else if (t == LUA_TSTRING) { + 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 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 *n_string_field_copy(lua_State * L, int name_index, const char *dflt) +{ + char *i; + lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L, -2); + if (lua_type(L,-1) == LUA_TSTRING) { + i = xstrdup(lua_tostring(L, -1)); + } else if (dflt == NULL) { + i = NULL; + } else { + i = xstrdup(dflt); + } + lua_pop(L, 1); + return i; +} + +static const char *n_string_field(lua_State * L, int name_index) +{ + lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L, -2); + return lua_tostring(L,-1); +} + +static int n_some_field(lua_State * L, int name_index) +{ + lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L, -2); + return lua_type(L,-1); +} + +/*static void init_font_string_pointers(lua_State * L){}*/ + +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_rawlen(L, -1); i++) { + lua_rawgeti(L, -1, i); + if (lua_istable(L, -1)) { + lua_rawgeti(L, -1, 1); + if (lua_type(L,-1) == LUA_TSTRING) { + const char *s = lua_tostring(L, -1); + if (lua_key_eq(s, font)) { + l += 5; + ff = 1; + } else if (lua_key_eq(s, char)) { + if (ff == 0) { + l += 5; + } + l += 5; + ff = 1; + } else if (lua_key_eq(s, slot)) { + l += 10; + ff = 1; + } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) { + ; + } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) { + l++; + } else if (lua_key_eq(s, rule)) { + l += 9; + } else if (lua_key_eq(s, right) || lua_key_eq(s, node) + || lua_key_eq(s, down) || lua_key_eq(s, image)) { + l += 5; + } else if (lua_key_eq(s, scale)) { + l += sizeof(float) + 1; + } else if (lua_key_eq(s, special) || lua_key_eq(s, lua)) { + size_t len; + lua_rawgeti(L, -2, 2); + if (lua_type(L,-1) == LUA_TSTRING) { + (void) lua_tolstring(L, -1, &len); + lua_pop(L, 1); + if (len > 0) { + l = (int) (l + 5 + (int) len); + } + } else { + lua_pop(L, 1); + normal_error("vf command","invalid packet special"); + /* fprintf(stdout, "invalid packet special!\n"); */ + } + } else { + normal_error("vf command","unknown packet command"); + /* fprintf(stdout, "unknown packet command %s!\n", s); */ + } + } else { + normal_error("vf command","no packet command"); + /* fprintf(stdout, "no packet command!\n"); */ + } + lua_pop(L, 1); /* command name */ + } + lua_pop(L, 1); /* item */ + } + return l; +} + +static 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, internal_font_number f, int atsize) +{ + int i, n, m; + size_t l; + int cmd; + const char *s; + eight_bits *cpackets, *cp; + int ff = 0; + int max_f = 0; + int pc = count_char_packet_bytes(L); + if (pc <= 0) + return; + while (l_fonts[(max_f + 1)] != 0) + max_f++; + cp = cpackets = xmalloc((unsigned) (pc + 1)); + for (i = 1; i <= (int) lua_rawlen(L, -1); i++) { + lua_rawgeti(L, -1, i); + if (lua_istable(L, -1)) { + /* fetch the command code */ + lua_rawgeti(L, -1, 1); + if (lua_type(L,-1) == LUA_TSTRING) { + s = lua_tostring(L, -1); + cmd = 0; + if (lua_key_eq(s, font)) { + cmd = packet_font_code; + } else if (lua_key_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 (lua_key_eq(s, slot)) { + cmd = packet_nop_code; + lua_rawgeti(L, -2, 2); + n = (int) luaL_checkinteger(L, -1); + if (n ==0) { + ff = f; + } else { + ff = (n > max_f ? l_fonts[1] : l_fonts[n]); + } + lua_rawgeti(L, -3, 3); + n = (int) luaL_checkinteger(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 (lua_key_eq(s, comment) || lua_key_eq(s, nop)) { + cmd = packet_nop_code; + } else if (lua_key_eq(s, node)) { + cmd = packet_node_code; + } else if (lua_key_eq(s, push)) { + cmd = packet_push_code; + } else if (lua_key_eq(s, pop)) { + cmd = packet_pop_code; + } else if (lua_key_eq(s, rule)) { + cmd = packet_rule_code; + } else if (lua_key_eq(s, right)) { + cmd = packet_right_code; + } else if (lua_key_eq(s, down)) { + cmd = packet_down_code; + } else if (lua_key_eq(s, special)) { + cmd = packet_special_code; + } else if (lua_key_eq(s, image)) { + cmd = packet_image_code; + } else if (lua_key_eq(s, scale)) { + cmd = packet_scale_code; + } else if (lua_key_eq(s, lua)) { + cmd = packet_lua_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) luaL_checkinteger(L, -1); + if (n == 0) { + ff = n; + } else { + 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) luaL_checkinteger(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) luaL_checkinteger(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) luaL_checkinteger(L, -1); + do_store_four(sp_to_dvi(n, atsize)); + lua_rawgeti(L, -3, 3); + n = (int) luaL_checkinteger(L, -1); + do_store_four(sp_to_dvi(n, atsize)); + lua_pop(L, 2); + break; + case packet_special_code: + case packet_lua_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); + s = luaL_checklstring(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_REGISTRYINDEX); /* ... */ + do_store_four(n); + break; + case packet_nop_code: + break; + case packet_scale_code: + append_packet(cmd); + lua_rawgeti(L, -2, 2); + append_float(&cp, (float) luaL_checknumber(L, -1)); + lua_pop(L, 1); + break; + default: + normal_error("vf command","invalid packet code"); + /* fprintf(stdout, "Unknown char packet code %s\n", s); */ + } + } + lua_pop(L, 1); /* command code */ + } else { + normal_error("vf command","commands has to be a tbale"); + /* fprintf(stdout, "Found a `commands' item that is not a table\n"); */ + } + 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");*/ + lua_key_rawgeti(cidinfo); + if (lua_istable(L, -1)) { + i = lua_numeric_field_by_index(L,lua_key_index(version), 0); + set_font_cidversion(f, i); + i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0); + set_font_cidsupplement(f, i); + s = n_string_field_copy(L, lua_key_index(registry), "Adobe"); /* Adobe-Identity-0 */ + set_font_cidregistry(f, s); + s = n_string_field_copy(L, lua_key_index(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, t; + const char *s; + /*lua_getfield(L, -1, "parameters");*/ + lua_key_rawgeti(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_type(L, -2) == LUA_TNUMBER) { + i = (int) lua_tointeger(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_type(L, -1) == LUA_TNUMBER) { + n = lua_roundnumber(L, -1); /* round ? */ + set_font_param(f, i, n); + } + lua_pop(L, 1); + } + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + t = lua_type(L,-2); + if (t == LUA_TNUMBER) { + i = (int) lua_tointeger(L, -2); + if (i >= 8) { + if (lua_type(L,-1) == LUA_TNUMBER) { + n = lua_roundnumber(L, -1); + } else { + n = 0; + } + set_font_param(f, i, n); + } + } else if (t == LUA_TSTRING) { + s = lua_tostring(L, -2); + if (lua_type(L,-1) == LUA_TNUMBER) { + n = lua_roundnumber(L, -1); + } else { + n = 0; + } + if (lua_key_eq(s, slant)) { + set_font_param(f, slant_code, n); + } else if (lua_key_eq(s, space)) { + set_font_param(f, space_code, n); + } else if (lua_key_eq(s, space_stretch)) { + set_font_param(f, space_stretch_code, n); + } else if (lua_key_eq(s, space_shrink)) { + set_font_param(f, space_shrink_code, n); + } else if (lua_key_eq(s, x_height)) { + set_font_param(f, x_height_code, n); + } else if (lua_key_eq(s, quad)) { + set_font_param(f, quad_code, n); + } else if (lua_key_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, t; + /*lua_getfield(L, -1, "MathConstants");*/ + lua_key_rawgeti(MathConstants); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + t = lua_type(L,-2); + if (t == LUA_TNUMBER) { + i = (int) lua_tointeger(L, -2); + } else if (t == LUA_TSTRING) { + i = ff_checkoption(L, -2, NULL, MATH_param_names); + } + n = (int) lua_roundnumber(L, -1); + if (i > 0) { + set_font_math_param(f, i, n); + } + lua_pop(L, 1); /* pop value */ + } + set_font_oldmath(f,false); + } else { + set_font_oldmath(f,true); + } + lua_pop(L, 1); +} + +@ @c +#define MIN_INF -0x7FFFFFFF + +static void store_math_kerns(lua_State * L, int index, charinfo * co, int id) +{ + int l, k; + scaled ht, krn; + lua_key_direct_rawgeti(index); + if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) { + for (l = 0; l < k; l++) { + lua_rawgeti(L, -1, (l + 1)); + if (lua_istable(L, -1)) { + ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF); + krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF); + if (krn > MIN_INF && ht > MIN_INF) + add_charinfo_math_kern(co, id, ht, krn); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); +} + +@ @c +static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math) +{ + int k, r, t, lt, u, n; + 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 = lua_numeric_field_by_index(L, lua_key_index(width), 0); + set_charinfo_width(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(height), 0); + set_charinfo_height(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(depth), 0); + set_charinfo_depth(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(italic), 0); + set_charinfo_italic(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0); + set_charinfo_vert_italic(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(index), 0); + set_charinfo_index(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000); + set_charinfo_ef(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0); + set_charinfo_lp(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0); + set_charinfo_rp(co, j); + k = n_boolean_field(L, lua_key_index(used), 0); + set_charinfo_used(co, k); + s = n_string_field(L, lua_key_index(name)); + if (s != NULL) + set_charinfo_name(co, xstrdup(s)); + else + set_charinfo_name(co, NULL); + /* n_string_field leaves a value on stack*/ + lua_pop(L,1); + u = n_some_field(L,lua_key_index(tounicode)); + if (u == LUA_TNUMBER) { + u = lua_tointeger(L,-1); + if (u < 0) { + set_charinfo_tounicode(co, NULL); + } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) { + char *s = malloc(5); + sprintf(s,"%04X",(unsigned int) u); + set_charinfo_tounicode(co,s); + } else { + char *s = malloc(9); + u = u - 0x10000; + sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00)); + set_charinfo_tounicode(co,s); + } + } else if (u == LUA_TTABLE) { + n = lua_rawlen(L,-1); + u = 0; + for (k = 1; k <= n; k++) { + lua_rawgeti(L, -1, k); + if (lua_type(L,-1) == LUA_TNUMBER) { + u = lua_tointeger(L,-1); + } else { + lua_pop(L, 1); + break; + } + if (u < 0) { + u = -1; + lua_pop(L, 1); + break; + } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) { + u = u + 4; + } else { + u = u + 8; + } + lua_pop(L, 1); + } + if (u>0) { + char *s = malloc(u+1); + char *t = s ; + for (k = 1; k <= n; k++) { + lua_rawgeti(L, -1, k); + u = lua_tointeger(L,-1); + if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) { + sprintf(t,"%04X",(unsigned int) u); + t += 4; + } else { + u = u - 0x10000; + sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00)); + t += 8; + } + lua_pop(L, 1); + } + set_charinfo_tounicode(co,s); + } else { + set_charinfo_tounicode(co, NULL); + } + } else if (u == LUA_TSTRING) { + s = lua_tostring(L,-1); + set_charinfo_tounicode(co, xstrdup(s)); + } else { + set_charinfo_tounicode(co, NULL); + } + /* ... leaves a value on stack*/ + lua_pop(L,1); + + if (has_math) { + j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN); + set_charinfo_top_accent(co, j); + j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN); + set_charinfo_bot_accent(co, j); + k = lua_numeric_field_by_index(L, lua_key_index(next), -1); + if (k >= 0) { + set_charinfo_tag(co, list_tag); + set_charinfo_remainder(co, k); + } + + lua_key_rawgeti(extensible); + if (lua_istable(L, -1)) { + int top, bot, mid, rep; + top = lua_numeric_field_by_index(L, lua_key_index(top), 0); + bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0); + mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0); + rep = lua_numeric_field_by_index(L, lua_key_index(rep), 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 { + formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field", + font_name(f), (int) i); + } + } + lua_pop(L, 1); + + lua_key_rawgeti(horiz_variants); + 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 = lua_numeric_field_by_index(L, lua_key_index(glyph), 0); + extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0); + startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0); + endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0); + advance = lua_numeric_field_by_index(L, lua_key_index(advance), 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_key_rawgeti(vert_variants); + 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 = lua_numeric_field_by_index(L, lua_key_index(glyph), 0); + extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0); + startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0); + endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0); + advance = lua_numeric_field_by_index(L, lua_key_index(advance), 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_key_rawgeti(mathkern); + if (lua_istable(L, -1)) { + store_math_kerns(L,lua_key_index(top_left), co, top_left_kern); + store_math_kerns(L,lua_key_index(top_right), co, top_right_kern); + store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern); + store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern); + } + lua_pop(L, 1); + } + /* end of |has_math| */ + count_hash_items(L, kerns, nk); + if (nk > 0) { + /* kerns table still on stack */ + ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo)); + ctr = 0; + lua_pushnil(L); /* traverse hash */ + while (lua_next(L, -2) != 0) { + k = non_boundarychar; + lt = lua_type(L,-2); + if (lt == LUA_TNUMBER) { + k = (int) lua_tointeger(L, -2); /* adjacent char */ + if (k < 0) + k = non_boundarychar; + } else if (lt == LUA_TSTRING) { + s = lua_tostring(L, -2); + if (lua_key_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 { + formatted_warning("font", "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 { + formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field", + font_name(f), (int) i); + } + lua_pop(L, 1); + } + + /* packet commands */ + lua_key_rawgeti(commands); + 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, f, atsize); + } + } + lua_pop(L, 1); + + /* ligatures */ + count_hash_items(L, ligatures, nl); + if (nl > 0) { + /* ligatures table still on stack */ + cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo)); + ctr = 0; + lua_pushnil(L); /* traverse hash */ + while (lua_next(L, -2) != 0) { + k = non_boundarychar; + lt = lua_type(L,-2); + if (lt == LUA_TNUMBER) { + k = (int) lua_tointeger(L, -2); /* adjacent char */ + if (k < 0) { + k = non_boundarychar; + } + } else if (lt == LUA_TSTRING) { + s = lua_tostring(L, -2); + if (lua_key_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 = lua_numeric_field_by_index(L, lua_key_index(char), -1); /* ligature */ + } + if (r != -1 && k != non_boundarychar) { + t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings); + set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r); + ctr++; + } else { + formatted_warning("font", "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 { + formatted_warning("font", "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, lt; + 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 ; + boolean no_math = false; + + /* will we save a cache of the luat table? */ + + save_ref = 1; /* we start with ss = "yes" */ + ss = NULL; + ss = n_string_field(L, lua_key_index(cache)); + if (lua_key_eq(ss, no)) + save_ref = -1; + else if (lua_key_eq(ss, renew)) + save_ref = 0; + /* n_string_field leaves a value on stack*/ + lua_pop(L,1); + + /* the table is at stack index -1 */ + + s = n_string_field_copy(L,lua_key_index(area), ""); + set_font_area(f, s); + s = n_string_field_copy(L, lua_key_index(filename), NULL); + set_font_filename(f, s); + s = n_string_field_copy(L, lua_key_index(encodingname), NULL); + set_font_encodingname(f, s); + + s = n_string_field_copy(L, lua_key_index(name), NULL); + set_font_name(f, s); + s = n_string_field_copy(L, lua_key_index(fullname), font_name(f)); + set_font_fullname(f, s); + + if (s == NULL) { + formatted_error("font","lua-loaded font '%d' has no name!", f); + return false; + } + s = n_string_field_copy(L, lua_key_index(psname), NULL); + set_font_psname(f, s); + + i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0); + set_font_units_per_em(f, i); + i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360); + set_font_dsize(f, i); + i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f)); + set_font_size(f, i); + set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ; + i = lua_numeric_field_by_index(L,lua_key_index(direction), 0); + set_font_natural_dir(f, i); + i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0); + set_font_encodingbytes(f, (char) i); + i = n_boolean_field(L,lua_key_index(oldmath), 0); + set_font_oldmath(f, i); + i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0); + set_font_tounicode(f, (char) i); + + i = lua_numeric_field_by_index(L,lua_key_index(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 = lua_numeric_field_by_index(L,lua_key_index(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 = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par); + set_hyphen_char(f, i); + i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par); + set_skew_char(f, i); + i = n_boolean_field(L, lua_key_index(used), 0); + set_font_used(f, (char) i); + + s = n_string_field_copy(L, lua_key_index(attributes), NULL); + if (s != NULL && strlen(s) > 0) { + i = maketexstring(s); + set_pdf_font_attr(f, i); + } + free(s); + + i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings); + set_font_type(f, i); + i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings); + set_font_format(f, i); + i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings); + set_font_writingmode(f, i); + i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings); + set_font_identity(f, i); + i = n_enum_field(L, lua_key_index(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 */ + count_hash_items(L, fonts, n); + if (n > 0) { + /* font table still on stack */ + l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int))); + memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int))); + for (i = 1; i <= n; i++) { + lua_rawgeti(L, -1, i); + if (lua_istable(L, -1)) { + lua_key_rawgeti(id); + if (lua_isnumber(L, -1)) { + l_fonts[i] = (int) lua_tointeger(L, -1); + if (l_fonts[i] == 0) { + l_fonts[i] = (int) f; + } + lua_pop(L, 2); /* pop id and entry */ + continue; + } + lua_pop(L, 1); /* pop id */ + }; + ss = NULL; + if (lua_istable(L, -1)) { + ss = n_string_field(L, lua_key_index(name)); + /* string is anchored */ + lua_pop(L,1); + } + if (ss != NULL) { + t = lua_numeric_field_by_index(L, lua_key_index(size), -1000); + /* 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 { + formatted_error("font","invalid local font in lua-loaded font '%s'", font_name(f)); + } + lua_pop(L, 1); /* pop list entry */ + } + lua_pop(L, 1); /* pop font table */ + } else if (font_type(f) == virtual_font_type) { + formatted_error("font","invalid local fonts in lua-loaded font '%s'", 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 = n_boolean_field(L, lua_key_index(nomath), 0); + read_lua_parameters(L, f); + if (!no_math) { + read_lua_math_parameters(L, f); + if (n_boolean_field(L, lua_key_index(oldmath), 0)) { + set_font_oldmath(f,true); + } + + } else { + set_font_oldmath(f,true); + } + read_lua_cidinfo(L, f); + + /* characters */ + lua_key_rawgeti(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) { + 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) { + lt = lua_type(L,-2); + if (lt == LUA_TNUMBER) { + i = (int) lua_tointeger(L, -2); + if (i >= 0) { + font_char_from_lua(L, f, i, l_fonts, !no_math); + } + } else if (lt == LUA_TSTRING) { + const char *ss1 = lua_tostring(L, -2); + if (lua_key_eq(ss1, left_boundary)) { + font_char_from_lua(L, f, left_boundarychar, l_fonts, + !no_math); + } else if (lua_key_eq(ss1, 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 = lua_numeric_field_by_index(L, lua_key_index(step), 0); + if (fstep < 0) + fstep = 0; + if (fstep > 100) + fstep = 100; + if (fstep != 0) { + int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0); + int fstretch =lua_numeric_field_by_index(L, lua_key_index(stretch), 0); + int fexpand = n_boolean_field(L, lua_key_index(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); + } + } + + } else { + /* jikes, no characters */ + formatted_warning("font","lua-loaded font '%d' with name '%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 */ + formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f)); + } + if (l_fonts != NULL) + free(l_fonts); + return true; +} + +@* Ligaturing. + +@c +static void nesting_append(halfword nest1, halfword newn) +{ + halfword tail = tlink(nest1); + if (tail == null) { + couple_nodes(nest1, newn); + } else { + couple_nodes(tail, newn); + } + tlink(nest1) = newn; +} + +static void nesting_prepend(halfword nest1, halfword newn) +{ + halfword head = vlink(nest1); + couple_nodes(nest1, newn); + if (head == null) { + tlink(nest1) = newn; + } else { + couple_nodes(newn, head); + } +} + +static void nesting_prepend_list(halfword nest1, halfword newn) +{ + halfword head = vlink(nest1); + couple_nodes(nest1, newn); + if (head == null) { + tlink(nest1) = tail_of_list(newn); + } else { + halfword tail = tail_of_list(newn); + couple_nodes(tail, head); + } +} + +static int test_ligature(liginfo * lig, halfword left, halfword right) +{ + if (type(left) != glyph_node) + return 0; + 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; + 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); + } + tlink(root) = cur; + return root; +} + +static halfword handle_lig_word(halfword cur) +{ + halfword right = null; + if (type(cur) == 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; + } + 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; + /* 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); + 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); + 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) == 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) { + /* 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); + 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' + */ + /* is it tail necessary ? */ + halfword last1 = vlink(next), tail ; + uncouple_node(next); + try_couple_nodes(fwd, last1); + /* \.{{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 */ + return cur; + } + /* step-to-next-node */ + /* \.{--\\par} allows |vlink(cur)| to be null */ + cur = vlink(cur); + } + + return cur; +} + +@ Return value is the new tail, head should be a dummy + +@c +halfword handle_ligaturing(halfword head, halfword tail) +{ + halfword save_tail1 = null; /* trick to allow explicit |node==null| tests */ + halfword cur, prev; + + if (vlink(head) == null) + return tail; + if (tail != null) { + save_tail1 = 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) == boundary_node)) { + cur = handle_lig_word(cur); + } + prev = cur; + cur = vlink(cur); + } + if (prev == null) { + /* hh: looks bad to me */ + prev = tail; + } + + if (tail != null) { + try_couple_nodes(prev, save_tail1); + } + 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); + couple_nodes(prev, kern); + couple_nodes(kern, right); + /* update the attribute list (inherit from left) */ + delete_attribute_ref(node_attr(kern)); + add_node_attr_ref(node_attr(left)); + node_attr(kern) = node_attr(left); + } + } +} + +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); + couple_nodes(aft, kern); + try_couple_nodes(kern, next); + /* update the attribute list (inherit from left == aft) */ + delete_attribute_ref(node_attr(kern)); + add_node_attr_ref(node_attr(aft)); + node_attr(kern) = node_attr(aft); + } + } +} + +static void do_handle_kerning(halfword root, halfword init_left, halfword init_right) +{ + halfword cur = vlink(root); + halfword left = null; + 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); + if (vlink_pre_break(cur) != null) + tlink_pre_break(cur) = tail_of_list(vlink_pre_break(cur)); + 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; + } 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; +} +*/ + +halfword handle_kerning(halfword head, halfword tail) +{ + halfword save_link = null; + if (tail == null) { + tlink(head) = null; + do_handle_kerning(head, null, null); + } else { + 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) +{ + int i; + int top = lua_gettop(Luas); + if (!get_callback(Luas, callback_id)) { + lua_pop(Luas, 2); + return tail; + } + nodelist_to_lua(Luas, head); + nodelist_to_lua(Luas, tail); + if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) { + luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1)); + return tail; + } + fix_node_list(head); + lua_settop(Luas, top); + return tail; +} + +halfword new_ligkern(halfword head, halfword tail) +{ + int callback_id = 0; + 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 nest1 = new_node(nesting_node, 1); + halfword cur = vlink(head); + halfword aft = vlink(tail); + couple_nodes(nest1, cur); + tlink(nest1) = tail; + vlink(tail) = null; + do_handle_kerning(nest1, null, null); + couple_nodes(head, vlink(nest1)); + tail = tlink(nest1); + try_couple_nodes(tail, aft); + flush_node(nest1); + } + return tail; +} |