1% luafont.w
2%
3% Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
4%
5% This file is part of LuaTeX.
6%
7% LuaTeX is free software; you can redistribute it and/or modify it under
8% the terms of the GNU General Public License as published by the Free
9% Software Foundation; either version 2 of the License, or (at your
10% option) any later version.
11%
12% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15% License for more details.
16%
17% You should have received a copy of the GNU General Public License along
18% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
19
20@ @c
21
22
23#include "ptexlib.h"
24#include "lua/luatex-api.h"
25
26#define noVERBOSE
27
28const char *font_type_strings[] = { "unknown", "virtual", "real", NULL };
29const char *font_format_strings[] =
30    { "unknown", "type1", "type3", "truetype", "opentype", NULL };
31const char *font_embedding_strings[] =
32    { "unknown", "no", "subset", "full", NULL };
33
34const char *ligature_type_strings[] =
35    { "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "",
36    "|=:|>>", NULL
37};
38
39const char *MATH_param_names[] = {
40    "nil",
41    "ScriptPercentScaleDown",
42    "ScriptScriptPercentScaleDown",
43    "DelimitedSubFormulaMinHeight",
44    "DisplayOperatorMinHeight",
45    "MathLeading",
46    "AxisHeight",
47    "AccentBaseHeight",
48    "FlattenedAccentBaseHeight",
49    "SubscriptShiftDown",
50    "SubscriptTopMax",
51    "SubscriptBaselineDropMin",
52    "SuperscriptShiftUp",
53    "SuperscriptShiftUpCramped",
54    "SuperscriptBottomMin",
55    "SuperscriptBaselineDropMax",
56    "SubSuperscriptGapMin",
57    "SuperscriptBottomMaxWithSubscript",
58    "SpaceAfterScript",
59    "UpperLimitGapMin",
60    "UpperLimitBaselineRiseMin",
61    "LowerLimitGapMin",
62    "LowerLimitBaselineDropMin",
63    "StackTopShiftUp",
64    "StackTopDisplayStyleShiftUp",
65    "StackBottomShiftDown",
66    "StackBottomDisplayStyleShiftDown",
67    "StackGapMin",
68    "StackDisplayStyleGapMin",
69    "StretchStackTopShiftUp",
70    "StretchStackBottomShiftDown",
71    "StretchStackGapAboveMin",
72    "StretchStackGapBelowMin",
73    "FractionNumeratorShiftUp",
74    "FractionNumeratorDisplayStyleShiftUp",
75    "FractionDenominatorShiftDown",
76    "FractionDenominatorDisplayStyleShiftDown",
77    "FractionNumeratorGapMin",
78    "FractionNumeratorDisplayStyleGapMin",
79    "FractionRuleThickness",
80    "FractionDenominatorGapMin",
81    "FractionDenominatorDisplayStyleGapMin",
82    "SkewedFractionHorizontalGap",
83    "SkewedFractionVerticalGap",
84    "OverbarVerticalGap",
85    "OverbarRuleThickness",
86    "OverbarExtraAscender",
87    "UnderbarVerticalGap",
88    "UnderbarRuleThickness",
89    "UnderbarExtraDescender",
90    "RadicalVerticalGap",
91    "RadicalDisplayStyleVerticalGap",
92    "RadicalRuleThickness",
93    "RadicalExtraAscender",
94    "RadicalKernBeforeDegree",
95    "RadicalKernAfterDegree",
96    "RadicalDegreeBottomRaisePercent",
97    "MinConnectorOverlap",
98    "SubscriptShiftDownWithSuperscript",
99    "FractionDelimiterSize",
100    "FractionDelimiterDisplayStyleSize",
101    NULL,
102};
103
104/* here for now, may be useful elsewhere */
105
106int ff_checkoption (lua_State *L, int narg, const char *def,
107                                 const char *const lst[]);
108
109int ff_checkoption (lua_State *L, int narg, const char *def,
110                                 const char *const lst[]) {
111  const char *name = (def) ? luaL_optstring(L, narg, def) :
112                             luaL_checkstring(L, narg);
113  int i;
114  for (i=0; lst[i]; i++)
115    if (strcmp(lst[i], name) == 0)
116      return i;
117  return -1;
118}
119
120
121
122static void dump_intfield(lua_State * L, const char *n, int c)
123{
124    lua_pushstring(L, n);
125    lua_pushnumber(L, c);
126    lua_rawset(L, -3);
127}
128
129
130static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
131{
132    int i;
133    for (i = 0; i < l; i++) {
134        lua_newtable(L);
135    /* *INDENT-OFF* */
136    if (id==top_left_kern) {
137        dump_intfield(L, "height", co->top_left_math_kern_array[(2*i)]);
138        dump_intfield(L, "kern",   co->top_left_math_kern_array[(2*i)+1]);
139    } else if (id==top_right_kern) {
140        dump_intfield(L, "height", co->top_right_math_kern_array[(2*i)]);
141        dump_intfield(L, "kern",   co->top_right_math_kern_array[(2*i)+1]);
142    } else if (id==bottom_right_kern) {
143        dump_intfield(L, "height", co->bottom_right_math_kern_array[(2*i)]);
144        dump_intfield(L, "kern",   co->bottom_right_math_kern_array[(2*i)+1]);
145    } else if (id==bottom_left_kern) {
146        dump_intfield(L, "height", co->bottom_left_math_kern_array[(2*i)]);
147        dump_intfield(L, "kern",   co->bottom_left_math_kern_array[(2*i)+1]);
148    }
149    /* *INDENT-ON* */
150        lua_rawseti(L, -2, (i + 1));
151    }
152}
153
154
155static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
156{
157    liginfo *l;
158    kerninfo *ki;
159
160    lua_createtable(L, 0, 10);
161
162    lua_pushstring(L, "width");
163    lua_pushnumber(L, get_charinfo_width(co));
164    lua_rawset(L, -3);
165
166    lua_pushstring(L, "height");
167    lua_pushnumber(L, get_charinfo_height(co));
168    lua_rawset(L, -3);
169
170    lua_pushstring(L, "depth");
171    lua_pushnumber(L, get_charinfo_depth(co));
172    lua_rawset(L, -3);
173
174
175    if (get_charinfo_italic(co) != 0) {
176       lua_pushstring(L, "italic");
177       lua_pushnumber(L, get_charinfo_italic(co));
178       lua_rawset(L, -3);
179    }
180
181    if (get_charinfo_top_accent(co) !=0) {
182       lua_pushstring(L, "top_accent");
183       lua_pushnumber(L, get_charinfo_top_accent(co));
184       lua_rawset(L, -3);
185    }
186
187    if (get_charinfo_bot_accent(co) != 0) {
188       lua_pushstring(L, "bot_accent")	;
189       lua_pushnumber(L, get_charinfo_bot_accent(co));
190       lua_rawset(L, -3);
191    }
192
193    if (get_charinfo_ef(co) != 0) {
194        lua_pushstring(L, "expansion_factor");
195        lua_pushnumber(L, get_charinfo_ef(co));
196        lua_rawset(L, -3);
197    }
198
199    if (get_charinfo_lp(co) != 0) {
200        lua_pushstring(L, "left_protruding");
201        lua_pushnumber(L, get_charinfo_lp(co));
202        lua_rawset(L, -3);
203    }
204
205    if (get_charinfo_rp(co) != 0) {
206        lua_pushstring(L, "right_protruding");
207        lua_pushnumber(L, get_charinfo_rp(co));
208        lua_rawset(L, -3);
209    }
210
211    if (font_encodingbytes(f) == 2) {
212        lua_pushstring(L, "index");
213        lua_pushnumber(L, get_charinfo_index(co));
214        lua_rawset(L, -3);
215    }
216
217    if (get_charinfo_name(co) != NULL) {
218        lua_pushstring(L, "name");
219        lua_pushstring(L, get_charinfo_name(co));
220        lua_rawset(L, -3);
221    }
222
223    if (get_charinfo_tounicode(co) != NULL) {
224        lua_pushstring(L, "tounicode");
225        lua_pushstring(L, get_charinfo_tounicode(co));
226        lua_rawset(L, -3);
227    }
228
229    if (get_charinfo_tag(co) == list_tag) {
230        lua_pushstring(L, "next");
231        lua_pushnumber(L, get_charinfo_remainder(co));
232        lua_rawset(L, -3);
233    }
234
235    lua_pushstring(L, "used");
236    lua_pushboolean(L, (get_charinfo_used(co) ? true : false));
237    lua_rawset(L, -3);
238
239    if (get_charinfo_tag(co) == ext_tag) {
240        extinfo *h;
241        h = get_charinfo_hor_variants(co);
242        if (h != NULL) {
243            int i = 1;
244            lua_newtable(L);
245            while (h != NULL) {
246                lua_createtable(L, 0, 5);
247                dump_intfield(L, "glyph", h->glyph);
248                dump_intfield(L, "extender", h->extender);
249                dump_intfield(L, "start", h->start_overlap);
250                dump_intfield(L, "end", h->end_overlap);
251                dump_intfield(L, "advance", h->advance);
252                lua_rawseti(L, -2, i);
253                i++;
254                h = h->next;
255            }
256            lua_setfield(L, -2, "horiz_variants");
257        }
258        h = get_charinfo_vert_variants(co);
259        if (h != NULL) {
260            int i = 1;
261            lua_newtable(L);
262            while (h != NULL) {
263                lua_createtable(L, 0, 5);
264                dump_intfield(L, "glyph", h->glyph);
265                dump_intfield(L, "extender", h->extender);
266                dump_intfield(L, "start", h->start_overlap);
267                dump_intfield(L, "end", h->end_overlap);
268                dump_intfield(L, "advance", h->advance);
269                lua_rawseti(L, -2, i);
270                i++;
271                h = h->next;
272            }
273            lua_setfield(L, -2, "vert_variants");
274        }
275    }
276    ki = get_charinfo_kerns(co);
277    if (ki != NULL) {
278        int i;
279        lua_pushstring(L, "kerns");
280        lua_createtable(L, 10, 1);
281        for (i = 0; !kern_end(ki[i]); i++) {
282            if (kern_char(ki[i]) == right_boundarychar) {
283                lua_pushstring(L, "right_boundary");
284            } else {
285                lua_pushnumber(L, kern_char(ki[i]));
286            }
287            lua_pushnumber(L, kern_kern(ki[i]));
288            lua_rawset(L, -3);
289        }
290        lua_rawset(L, -3);
291    }
292    l = get_charinfo_ligatures(co);
293    if (l != NULL) {
294        int i;
295        lua_pushstring(L, "ligatures");
296        lua_createtable(L, 10, 1);
297        for (i = 0; !lig_end(l[i]); i++) {
298            if (lig_char(l[i]) == right_boundarychar) {
299                lua_pushstring(L, "right_boundary");
300            } else {
301                lua_pushnumber(L, lig_char(l[i]));
302            }
303            lua_createtable(L, 0, 2);
304            lua_pushstring(L, "type");
305            lua_pushnumber(L, lig_type(l[i]));
306            lua_rawset(L, -3);
307            lua_pushstring(L, "char");
308            lua_pushnumber(L, lig_replacement(l[i]));
309            lua_rawset(L, -3);
310            lua_rawset(L, -3);
311        }
312        lua_rawset(L, -3);
313    }
314
315    lua_newtable(L);
316    {
317    int i, j;
318    i = get_charinfo_math_kerns(co, top_right_kern);
319    j = 0;
320    if (i > 0) {
321        j++;
322        lua_newtable(L);
323        dump_math_kerns(L, co, i, top_right_kern);
324        lua_setfield(L, -2, "top_right");
325    }
326    i = get_charinfo_math_kerns(co, top_left_kern);
327    if (i > 0) {
328        j++;
329        lua_newtable(L);
330        dump_math_kerns(L, co, i, top_left_kern);
331        lua_setfield(L, -2, "top_left");
332    }
333    i = get_charinfo_math_kerns(co, bottom_right_kern);
334    if (i > 0) {
335        j++;
336        lua_newtable(L);
337        dump_math_kerns(L, co, i, bottom_right_kern);
338        lua_setfield(L, -2, "bottom_right");
339    }
340    i = get_charinfo_math_kerns(co, bottom_left_kern);
341    if (i > 0) {
342        j++;
343        lua_newtable(L);
344        dump_math_kerns(L, co, i, bottom_left_kern);
345        lua_setfield(L, -2, "bottom_left");
346    }
347    if (j > 0)
348        lua_setfield(L, -2, "mathkern");
349    else
350        lua_pop(L, 1);
351    }
352}
353
354static void write_lua_parameters(lua_State * L, int f)
355{
356    int k;
357    lua_newtable(L);
358    for (k = 1; k <= font_params(f); k++) {
359        lua_pushnumber(L, font_param(f, k));
360        switch (k) {
361        case slant_code:
362            lua_setfield(L, -2, "slant");
363            break;
364        case space_code:
365            lua_setfield(L, -2, "space");
366            break;
367        case space_stretch_code:
368            lua_setfield(L, -2, "space_stretch");
369            break;
370        case space_shrink_code:
371            lua_setfield(L, -2, "space_shrink");
372            break;
373        case x_height_code:
374            lua_setfield(L, -2, "x_height");
375            break;
376        case quad_code:
377            lua_setfield(L, -2, "quad");
378            break;
379        case extra_space_code:
380            lua_setfield(L, -2, "extra_space");
381            break;
382        default:
383            lua_rawseti(L, -2, k);
384        }
385    }
386    lua_setfield(L, -2, "parameters");
387}
388
389@ @c
390static void write_lua_math_parameters(lua_State * L, int f)
391{
392    int k;
393    lua_newtable(L);
394    for (k = 1; k <= font_math_params(f); k++) {
395        lua_pushnumber(L, font_math_param(f, k));
396        if (k <= MATH_param_max) {
397            lua_setfield(L, -2, MATH_param_names[k]);
398        } else {
399            lua_rawseti(L, -2, k);
400        }
401    }
402    lua_setfield(L, -2, "MathConstants");
403}
404
405
406
407int font_to_lua(lua_State * L, int f)
408{
409    int k;
410    charinfo *co;
411    if (font_cache_id(f) > 0) {
412        /* fetch the table from the registry if it was
413           saved there by |font_from_lua()| */
414        lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f));
415        /* fontdimens can be changed from tex code */
416        write_lua_parameters(L, f);
417        return 1;
418    }
419
420    lua_newtable(L);
421    lua_pushstring(L, font_name(f));
422    lua_setfield(L, -2, "name");
423    if (font_area(f) != NULL) {
424        lua_pushstring(L, font_area(f));
425        lua_setfield(L, -2, "area");
426    }
427    if (font_filename(f) != NULL) {
428        lua_pushstring(L, font_filename(f));
429        lua_setfield(L, -2, "filename");
430    }
431    if (font_fullname(f) != NULL) {
432        lua_pushstring(L, font_fullname(f));
433        lua_setfield(L, -2, "fullname");
434    }
435    if (font_psname(f) != NULL) {
436        lua_pushstring(L, font_psname(f));
437        lua_setfield(L, -2, "psname");
438    }
439    if (font_encodingname(f) != NULL) {
440        lua_pushstring(L, font_encodingname(f));
441        lua_setfield(L, -2, "encodingname");
442    }
443
444    lua_pushboolean(L, (font_used(f) ? true : false));
445    lua_setfield(L, -2, "used");
446
447
448    lua_pushstring(L, font_type_strings[font_type(f)]);
449    lua_setfield(L, -2, "type");
450    lua_pushstring(L, font_format_strings[font_format(f)]);
451    lua_setfield(L, -2, "format");
452    lua_pushstring(L, font_embedding_strings[font_embedding(f)]);
453    lua_setfield(L, -2, "embedding");
454
455    lua_pushnumber(L, font_units_per_em(f));
456    lua_setfield(L, -2, "units_per_em");
457    lua_pushnumber(L, font_size(f));
458    lua_setfield(L, -2, "size");
459    lua_pushnumber(L, font_dsize(f));
460    lua_setfield(L, -2, "designsize");
461    lua_pushnumber(L, font_checksum(f));
462    lua_setfield(L, -2, "checksum");
463    lua_pushnumber(L, font_slant(f));
464    lua_setfield(L, -2, "slant");
465    lua_pushnumber(L, font_extend(f));
466    lua_setfield(L, -2, "extend");
467    lua_pushnumber(L, font_natural_dir(f));
468    lua_setfield(L, -2, "direction");
469    lua_pushnumber(L, font_encodingbytes(f));
470    lua_setfield(L, -2, "encodingbytes");
471    lua_pushnumber(L, font_tounicode(f));
472    lua_setfield(L, -2, "tounicode");
473
474    /* pdf parameters */
475    /* skip the first four for now, that are very much interal */
476#if 0
477       if (pdf_font_num(f) != 0) {
478       lua_pushnumber(L,pdf_font_num(f));
479       lua_setfield(L,-2,"pdf_num");
480       }
481#endif
482    /* the next one is read only */
483    if (font_max_shrink(f) != 0) {
484        lua_pushnumber(L, font_max_shrink(f));
485        lua_setfield(L, -2, "max_shrink");
486    }
487    if (font_max_stretch(f) != 0) {
488        lua_pushnumber(L, font_max_stretch(f));
489        lua_setfield(L, -2, "max_stretch");
490    }
491    if (font_step(f) != 0) {
492        lua_pushnumber(L, font_step(f));
493        lua_setfield(L, -2, "step");
494    }
495    if (font_auto_expand(f) != 0) {
496        lua_pushboolean(L, font_auto_expand(f));
497        lua_setfield(L, -2, "auto_expand");
498    }
499    if (pdf_font_attr(f) != 0) {
500        char *s = makecstring(pdf_font_attr(f));
501        lua_pushstring(L, s);
502        free(s);
503        lua_setfield(L, -2, "attributes");
504    }
505
506    /* params */
507    write_lua_parameters(L, f);
508    write_lua_math_parameters(L, f);
509
510    /* chars */
511    lua_createtable(L, font_tables[f]->charinfo_size, 0);       /* all characters */
512
513    if (has_left_boundary(f)) {
514        co = get_charinfo(f, left_boundarychar);
515        font_char_to_lua(L, f, co);
516        lua_setfield(L, -2, "left_boundary");
517    }
518    if (has_right_boundary(f)) {
519        co = get_charinfo(f, right_boundarychar);
520        font_char_to_lua(L, f, co);
521        lua_setfield(L, -2, "right_boundary");
522    }
523
524    for (k = font_bc(f); k <= font_ec(f); k++) {
525        if (quick_char_exists(f, k)) {
526            lua_pushnumber(L, k);
527            co = get_charinfo(f, k);
528            font_char_to_lua(L, f, co);
529            lua_rawset(L, -3);
530        }
531    }
532    lua_setfield(L, -2, "characters");
533
534    if (font_cache_id(f) == 0) {        /* renew */
535        int r;
536        lua_pushvalue(L, -1);
537        r = luaL_ref(L, LUA_REGISTRYINDEX);     /* pops the table */
538        set_font_cache_id(f, r);
539    }
540    return 1;
541}
542
543static int count_hash_items(lua_State * L, int name_index)
544{
545    int n = -1;
546    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
547    lua_rawget(L, -2);
548    if (!lua_isnil(L, -1)) {
549        if (lua_istable(L, -1)) {
550            n = 0;
551            /* now find the number */
552            lua_pushnil(L);     /* first key */
553            while (lua_next(L, -2) != 0) {
554                n++;
555                lua_pop(L, 1);
556            }
557        }
558    }
559    lua_pop(L, 1);
560    return n;
561}
562
563@ @c
564#define streq(a,b) (strcmp(a,b)==0)
565
566#define append_packet(k) { *(cp++) = (eight_bits) (k); }
567
568#define do_store_four(l) {                 \
569    append_packet((l & 0xFF000000) >> 24); \
570    append_packet((l & 0x00FF0000) >> 16); \
571    append_packet((l & 0x0000FF00) >> 8);  \
572    append_packet((l & 0x000000FF));       \
573}
574
575@ @c
576static void append_float(eight_bits ** cpp, float a)
577{
578    unsigned int i;
579    eight_bits *cp = *cpp;
580    union U {
581        float a;
582        eight_bits b[sizeof(float)];
583    } u;
584    u.a = a;
585    for (i = 0; i < sizeof(float); i++)
586        append_packet(u.b[i]);
587    *cpp = cp;
588}
589
590//#define lua_roundnumber(a,b) (int)floor((double)lua_tonumber(L,-1)+0.5)
591
592
593/* static int n_numeric_field(lua_State * L, int name_index, int dflt) */
594/* { */
595/*     register int i = dflt; */
596/*     lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /\* fetch the stringptr *\/ */
597/*     lua_rawget(L, -2); */
598/*     if (lua_type(L, -1) == LUA_TNUMBER) { */
599/*         i = lua_roundnumber(L, -1); */
600/*     } */
601/*     lua_pop(L, 1); */
602/*     return i; */
603/* } */
604
605
606
607
608/* static int enum_field(lua_State * L, const char *name, int dflt, */
609/*                       const char **values) */
610/* { */
611/*     int k; */
612/*     const char *s; */
613/*     int i = dflt; */
614/*     lua_pushstring(L, name); */
615/*     lua_rawget(L, -2); */
616/*     if (lua_isnumber(L, -1)) { */
617/*         i=(int)lua_tonumber(L, -1); */
618/*     } else if (lua_isstring(L, -1)) { */
619/*         s = lua_tostring(L, -1); */
620/*         k = 0; */
621/*         while (values[k] != NULL) { */
622/*             if (strcmp(values[k], s) == 0) { */
623/*                 i = k; */
624/*                 break; */
625/*             } */
626/*             k++; */
627/*         } */
628/*     } */
629/*     lua_pop(L, 1); */
630/*     return i; */
631/* } */
632
633static int n_enum_field(lua_State * L, int name_index, int dflt,
634                      const char **values)
635{
636    int k;
637    const char *s;
638    int i = dflt;
639    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
640    lua_rawget(L, -2);
641    if (lua_isnumber(L, -1)) {
642        i=(int)lua_tonumber(L, -1);
643    } else if (lua_isstring(L, -1)) {
644        s = lua_tostring(L, -1);
645        k = 0;
646        while (values[k] != NULL) {
647            if (strcmp(values[k], s) == 0) {
648                i = k;
649                break;
650            }
651            k++;
652        }
653    }
654    lua_pop(L, 1);
655    return i;
656}
657
658
659
660/* static int boolean_field(lua_State * L, const char *name, int dflt) */
661/* { */
662/*     int i = dflt; */
663/*     lua_pushstring(L, name); */
664/*     lua_rawget(L, -2); */
665/*     if (lua_isboolean(L, -1)) { */
666/*         i = lua_toboolean(L, -1); */
667/*     } */
668/*     lua_pop(L, 1); */
669/*     return i; */
670/* } */
671
672static int n_boolean_field(lua_State * L, int name_index, int dflt)
673{
674    int i = dflt;
675    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
676    lua_rawget(L, -2);
677    if (lua_isboolean(L, -1)) {
678        i = lua_toboolean(L, -1);
679    }
680    lua_pop(L, 1);
681    return i;
682}
683
684
685static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
686{
687    char *i;
688    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
689    lua_rawget(L, -2);
690    if (lua_isstring(L, -1)) {
691        i = xstrdup(lua_tostring(L, -1));
692    } else if (dflt == NULL) {
693        i = NULL;
694    } else {
695        i = xstrdup(dflt);
696    }
697    lua_pop(L, 1);
698    return i;
699}
700
701static const char *n_string_field(lua_State * L, int name_index)
702{
703    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
704    lua_rawget(L, -2);
705    return lua_tostring(L,-1);
706}
707/*static void init_font_string_pointers(lua_State * L){}*/
708
709static int count_char_packet_bytes(lua_State * L)
710{
711    register int i;
712    register int l = 0;
713    int ff = 0;
714    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
715        lua_rawgeti(L, -1, i);
716        if (lua_istable(L, -1)) {
717            lua_rawgeti(L, -1, 1);
718            if (lua_isstring(L, -1)) {
719                const char *s = lua_tostring(L, -1);
720                if (lua_key_eq(s, font)) {
721                    l += 5;
722                    ff = 1;
723                } else if (lua_key_eq(s, char)) {
724                    if (ff == 0) {
725                        l += 5;
726                    }
727                    l += 5;
728                    ff = 1;
729                } else if (lua_key_eq(s, slot)) {
730                    l += 10;
731                    ff = 1;
732                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
733                    ;
734                } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
735                    l++;
736                } else if (lua_key_eq(s, rule)) {
737                    l += 9;
738                } else if (lua_key_eq(s, right) || lua_key_eq(s, node)
739                           || lua_key_eq(s, down) || lua_key_eq(s, image)) {
740                    l += 5;
741                } else if (lua_key_eq(s, scale)) {
742                    l += sizeof(float) + 1;
743                } else if (lua_key_eq(s, special) || lua_key_eq(s, lua)) {
744                    size_t len;
745                    lua_rawgeti(L, -2, 2);
746                    if (lua_isstring(L, -1)) {
747                        (void) lua_tolstring(L, -1, &len);
748                        lua_pop(L, 1);
749                        if (len > 0) {
750                            l = (int) (l + 5 + (int) len);
751                        }
752                    } else {
753                        lua_pop(L, 1);
754                        fprintf(stdout, "invalid packet special!\n");
755                    }
756                } else {
757                    fprintf(stdout, "unknown packet command %s!\n", s);
758                }
759            } else {
760                fprintf(stdout, "no packet command!\n");
761            }
762            lua_pop(L, 1);      /* command name */
763        }
764        lua_pop(L, 1);          /* item */
765    }
766    return l;
767}
768
769static scaled sp_to_dvi(halfword sp, halfword atsize)
770{
771    double result, mult;
772    mult = (double) (atsize / 65536.0);
773    result = (double) (sp * 16.0);
774    return floor(result / mult);
775}
776
777@ @c
778static void
779read_char_packets(lua_State * L, int *l_fonts, charinfo * co, int atsize)
780{
781    int i, n, m;
782    size_t l;
783    int cmd;
784    const char *s;
785    eight_bits *cpackets, *cp;
786    int ff = 0;
787    int max_f = 0;
788    int pc = count_char_packet_bytes(L);
789    if (pc <= 0)
790        return;
791    assert(l_fonts != NULL);
792    assert(l_fonts[1] != 0);
793    while (l_fonts[(max_f + 1)] != 0)
794        max_f++;
795
796    cp = cpackets = xmalloc((unsigned) (pc + 1));
797    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
798        lua_rawgeti(L, -1, i);
799        if (lua_istable(L, -1)) {
800            /* fetch the command code */
801            lua_rawgeti(L, -1, 1);
802            if (lua_isstring(L, -1)) {
803                s = lua_tostring(L, -1);
804                cmd = 0;
805                if (lua_key_eq(s, font)) {
806                    cmd = packet_font_code;
807                } else if (lua_key_eq(s, char)) {
808                    cmd = packet_char_code;
809                    if (ff == 0) {
810                        append_packet(packet_font_code);
811                        ff = l_fonts[1];
812                        do_store_four(ff);
813                    }
814                } else if (lua_key_eq(s, slot)) {
815                    cmd = packet_nop_code;
816                    lua_rawgeti(L, -2, 2);
817                    n = (int) luaL_checkinteger(L, -1);
818                    ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
819                    lua_rawgeti(L, -3, 3);
820                    n = (int) luaL_checkinteger(L, -1);
821                    lua_pop(L, 2);
822                    append_packet(packet_font_code);
823                    do_store_four(ff);
824                    append_packet(packet_char_code);
825                    do_store_four(n);
826                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
827                    cmd = packet_nop_code;
828                } else if (lua_key_eq(s, node)) {
829                    cmd = packet_node_code;
830                } else if (lua_key_eq(s, push)) {
831                    cmd = packet_push_code;
832                } else if (lua_key_eq(s, pop)) {
833                    cmd = packet_pop_code;
834                } else if (lua_key_eq(s, rule)) {
835                    cmd = packet_rule_code;
836                } else if (lua_key_eq(s, right)) {
837                    cmd = packet_right_code;
838                } else if (lua_key_eq(s, down)) {
839                    cmd = packet_down_code;
840                } else if (lua_key_eq(s, special)) {
841                    cmd = packet_special_code;
842                } else if (lua_key_eq(s, image)) {
843                    cmd = packet_image_code;
844                } else if (lua_key_eq(s, scale)) {
845                    cmd = packet_scale_code;
846                } else if (lua_key_eq(s, lua)) {
847                    cmd = packet_lua_code;
848                }
849
850                switch (cmd) {
851                case packet_push_code:
852                case packet_pop_code:
853                    append_packet(cmd);
854                    break;
855                case packet_font_code:
856                    append_packet(cmd);
857                    lua_rawgeti(L, -2, 2);
858                    n = (int) luaL_checkinteger(L, -1);
859                    ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
860                    do_store_four(ff);
861                    lua_pop(L, 1);
862                    break;
863                case packet_node_code:
864                    append_packet(cmd);
865                    lua_rawgeti(L, -2, 2);
866                    n = copy_node_list(nodelist_from_lua(L));
867                    do_store_four(n);
868                    lua_pop(L, 1);
869                    break;
870                case packet_char_code:
871                    append_packet(cmd);
872                    lua_rawgeti(L, -2, 2);
873                    n = (int) luaL_checkinteger(L, -1);
874                    do_store_four(n);
875                    lua_pop(L, 1);
876                    break;
877                case packet_right_code:
878                case packet_down_code:
879                    append_packet(cmd);
880                    lua_rawgeti(L, -2, 2);
881                    n = (int) luaL_checkinteger(L, -1);
882                    do_store_four(sp_to_dvi(n, atsize));
883                    lua_pop(L, 1);
884                    break;
885                case packet_rule_code:
886                    append_packet(cmd);
887                    lua_rawgeti(L, -2, 2);
888                    n = (int) luaL_checkinteger(L, -1);
889                    do_store_four(sp_to_dvi(n, atsize));
890                    lua_rawgeti(L, -3, 3);
891                    n = (int) luaL_checkinteger(L, -1);
892                    do_store_four(sp_to_dvi(n, atsize));
893                    lua_pop(L, 2);
894                    break;
895                case packet_special_code:
896                case packet_lua_code:
897                    append_packet(cmd);
898                    lua_rawgeti(L, -2, 2);
899                    s = luaL_checklstring(L, -1, &l);
900                    if (l > 0) {
901                        do_store_four(l);
902                        m = (int) l;
903                        while (m > 0) {
904                            n = *s++;
905                            m--;
906                            append_packet(n);
907                        }
908                    }
909                    lua_pop(L, 1);
910                    break;
911                case packet_image_code:
912                    append_packet(cmd);
913                    lua_rawgeti(L, -2, 2);      /* img/imgtable? ... */
914                    if (lua_istable(L, -1)) {   /* imgtable ... */
915                        lua_getglobal(L, "img");        /* imglib imgtable ... */
916                        lua_pushstring(L, "new");       /* `new' imglib imgtable ... */
917                        lua_gettable(L, -2);    /* f imglib imgtable ... */
918                        lua_insert(L, -3);      /* imglib imgtable f ... */
919                        lua_pop(L, 1);  /* imgtable f ... */
920                        lua_call(L, 1, 1);
921                    }           /* img ... */
922                    luaL_checkudata(L, -1, TYPE_IMG);   /* img ... --- just typecheck */
923                    n = luaL_ref(L, LUA_REGISTRYINDEX);  /* ... */
924                    do_store_four(n);
925                    break;
926                case packet_nop_code:
927                    break;
928                case packet_scale_code:
929                    append_packet(cmd);
930                    lua_rawgeti(L, -2, 2);
931                    append_float(&cp, (float) luaL_checknumber(L, -1));
932                    lua_pop(L, 1);
933                    break;
934                default:
935                    fprintf(stdout, "Unknown char packet code %s\n", s);
936                }
937            }
938            lua_pop(L, 1);      /* command code */
939        } else {
940            fprintf(stdout, "Found a `commands' item that is not a table\n");
941        }
942        lua_pop(L, 1);          /* command table */
943    }
944    append_packet(packet_end_code);
945    set_charinfo_packets(co, cpackets);
946    return;
947}
948
949@ @c
950static void read_lua_cidinfo(lua_State * L, int f)
951{
952    int i;
953    char *s;
954    //lua_getfield(L, -1, "cidinfo");
955    lua_key_rawgeti(cidinfo);
956    if (lua_istable(L, -1)) {
957        i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
958        set_font_cidversion(f, i);
959        i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
960        set_font_cidsupplement(f, i);
961        s = n_string_field_copy(L, lua_key_index(registry), "Adobe");       /* Adobe-Identity-0 */
962        set_font_cidregistry(f, s);
963        s = n_string_field_copy(L, lua_key_index(ordering), "Identity");
964        set_font_cidordering(f, s);
965    }
966    lua_pop(L, 1);
967}
968
969
970@ @c
971static void read_lua_parameters(lua_State * L, int f)
972{
973    int i, n;
974    const char *s;
975    //lua_getfield(L, -1, "parameters");
976    lua_key_rawgeti(parameters);
977    if (lua_istable(L, -1)) {
978        /* the number of parameters is the max(IntegerKeys(L)),7) */
979        n = 7;
980        lua_pushnil(L);         /* first key */
981        while (lua_next(L, -2) != 0) {
982            if (lua_isnumber(L, -2)) {
983                i=(int)lua_tonumber(L, -2);
984                if (i > n)
985                    n = i;
986            }
987            lua_pop(L, 1);      /* pop value */
988        }
989        if (n > 7)
990            set_font_params(f, n);
991        /* sometimes it is handy to have all integer keys */
992        for (i = 1; i <= 7; i++) {
993            lua_rawgeti(L, -1, i);
994            if (lua_isnumber(L, -1)) {
995                n = lua_roundnumber(L, -1);
996                set_font_param(f, i, n);
997            }
998            lua_pop(L, 1);
999        }
1000        lua_pushnil(L);         /* first key */
1001        while (lua_next(L, -2) != 0) {
1002            if (lua_isnumber(L, -2)) {
1003                i = (int) lua_tointeger(L, -2);
1004                if (i >= 8) {
1005                    n = (lua_isnumber(L, -1) ? lua_roundnumber(L, -1) : 0);
1006                    set_font_param(f, i, n);
1007                }
1008            } else if (lua_isstring(L, -2)) {
1009                s = lua_tostring(L, -2);
1010                n = (lua_isnumber(L, -1) ? lua_roundnumber(L, -1) : 0);
1011                if (lua_key_eq(s, slant)) {
1012                    set_font_param(f, slant_code, n);
1013                } else if (lua_key_eq(s, space)) {
1014                    set_font_param(f, space_code, n);
1015                } else if (lua_key_eq(s, space_stretch)) {
1016                    set_font_param(f, space_stretch_code, n);
1017                } else if (lua_key_eq(s, space_shrink)) {
1018                    set_font_param(f, space_shrink_code, n);
1019                } else if (lua_key_eq(s, x_height)) {
1020                    set_font_param(f, x_height_code, n);
1021                } else if (lua_key_eq(s, quad)) {
1022                    set_font_param(f, quad_code, n);
1023                } else if (lua_key_eq(s, extra_space)) {
1024                    set_font_param(f, extra_space_code, n);
1025                }
1026            }
1027            lua_pop(L, 1);
1028        }
1029    }
1030    lua_pop(L, 1);
1031
1032}
1033
1034@ @c
1035static void read_lua_math_parameters(lua_State * L, int f)
1036{
1037    int i = 0, n = 0;
1038    //lua_getfield(L, -1, "MathConstants");
1039    lua_key_rawgeti(MathConstants);
1040    if (lua_istable(L, -1)) {
1041        lua_pushnil(L);
1042        while (lua_next(L, -2) != 0) {
1043            if (lua_isnumber(L, -2)) {
1044                i=(int)lua_tonumber(L, -2);
1045            } else if (lua_isstring(L, -2)) {
1046                i = ff_checkoption(L, -2, NULL, MATH_param_names);
1047            }
1048            n=(int)lua_tonumber(L, -1);
1049            if (i > 0) {
1050                set_font_math_param(f, i, n);
1051            }
1052            lua_pop(L, 1);      /* pop value */
1053        }
1054    }
1055    lua_pop(L, 1);
1056}
1057
1058@ @c
1059#define MIN_INF -0x7FFFFFFF
1060
1061
1062static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
1063{
1064    int l, k;
1065    scaled ht, krn;
1066    lua_rawgeti(L, LUA_REGISTRYINDEX, index);lua_rawget(L, -2);
1067    if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
1068        for (l = 0; l < k; l++) {
1069            lua_rawgeti(L, -1, (l + 1));
1070            if (lua_istable(L, -1)) {
1071	        ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
1072		krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
1073                if (krn > MIN_INF && ht > MIN_INF)
1074                    add_charinfo_math_kern(co, id, ht, krn);
1075            }
1076            lua_pop(L, 1);
1077        }
1078    }
1079    lua_pop(L, 1);
1080}
1081
1082@ @c
1083static void
1084font_char_from_lua(lua_State * L, internal_font_number f, int i,
1085                   int *l_fonts, boolean has_math)
1086{
1087    int k, r, t;
1088    charinfo *co;
1089    kerninfo *ckerns;
1090    liginfo *cligs;
1091    scaled j;
1092    const char *s;
1093    int nl = 0;                 /* number of ligature table items */
1094    int nk = 0;                 /* number of kern table items */
1095    int ctr = 0;
1096    int atsize = font_size(f);
1097    if (lua_istable(L, -1)) {
1098        co = get_charinfo(f, i);
1099        set_charinfo_tag(co, 0);
1100        j = lua_numeric_field_by_index(L, lua_key_index(width), 0);
1101        set_charinfo_width(co, j);
1102        j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
1103        set_charinfo_height(co, j);
1104        j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
1105        set_charinfo_depth(co, j);
1106        j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
1107        set_charinfo_italic(co, j);
1108        j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
1109        set_charinfo_index(co, j);
1110        j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 0);
1111        set_charinfo_ef(co, j);
1112        j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
1113        set_charinfo_lp(co, j);
1114        j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
1115        set_charinfo_rp(co, j);
1116        k = n_boolean_field(L, lua_key_index(used), 0);
1117        set_charinfo_used(co, k);
1118        s = n_string_field(L, lua_key_index(name));
1119        if (s != NULL)
1120            set_charinfo_name(co, xstrdup(s));
1121        else
1122            set_charinfo_name(co, NULL);
1123        /* n_string_field leaves a value on stack*/
1124        lua_pop(L,1);
1125        s = n_string_field(L, lua_key_index(tounicode));
1126        if (s != NULL)
1127            set_charinfo_tounicode(co, xstrdup(s));
1128        else
1129            set_charinfo_tounicode(co, NULL);
1130	/* n_string_field leaves a value on stack*/
1131        lua_pop(L,1);
1132        if (has_math) {
1133            j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
1134            set_charinfo_top_accent(co, j);
1135            j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
1136            set_charinfo_bot_accent(co, j);
1137            k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
1138            if (k >= 0) {
1139                set_charinfo_tag(co, list_tag);
1140                set_charinfo_remainder(co, k);
1141            }
1142
1143            lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(extensible));
1144            lua_rawget(L, -2);
1145            if (lua_istable(L, -1)) {
1146                int top, bot, mid, rep;
1147                top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
1148                bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
1149                mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
1150                rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0);
1151                if (top != 0 || bot != 0 || mid != 0 || rep != 0) {
1152                    set_charinfo_tag(co, ext_tag);
1153                    set_charinfo_extensible(co, top, bot, mid, rep);
1154                } else {
1155                    luatex_warn
1156                        ("lua-loaded font %s char [U+%X] has an invalid extensible field!",
1157                         font_name(f), (int) i);
1158                }
1159            }
1160            lua_pop(L, 1);
1161
1162            lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(horiz_variants));
1163            lua_rawget(L, -2);
1164            if (lua_istable(L, -1)) {
1165                int glyph, startconnect, endconnect, advance, extender;
1166                extinfo *h;
1167                set_charinfo_tag(co, ext_tag);
1168                set_charinfo_hor_variants(co, NULL);
1169                for (k = 1;; k++) {
1170                    lua_rawgeti(L, -1, k);
1171                    if (lua_istable(L, -1)) {
1172                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
1173                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
1174                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
1175                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
1176                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
1177                        h = new_variant(glyph, startconnect, endconnect,
1178                                        advance, extender);
1179                        add_charinfo_hor_variant(co, h);
1180                        lua_pop(L, 1);
1181                    } else {
1182                        lua_pop(L, 1);
1183                        break;
1184                    }
1185                }
1186            }
1187            lua_pop(L, 1);
1188
1189            lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(vert_variants));
1190            lua_rawget(L, -2);
1191            if (lua_istable(L, -1)) {
1192                int glyph, startconnect, endconnect, advance, extender;
1193                extinfo *h;
1194                set_charinfo_tag(co, ext_tag);
1195                set_charinfo_vert_variants(co, NULL);
1196                for (k = 1;; k++) {
1197                    lua_rawgeti(L, -1, k);
1198                    if (lua_istable(L, -1)) {
1199                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
1200                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
1201                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
1202                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
1203                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
1204                        h = new_variant(glyph, startconnect, endconnect,
1205                                        advance, extender);
1206                        add_charinfo_vert_variant(co, h);
1207                        lua_pop(L, 1);
1208                    } else {
1209                        lua_pop(L, 1);
1210                        break;
1211                    }
1212                }
1213            }
1214            lua_pop(L, 1);
1215
1216/* Here is a complete example:
1217
1218   |["mathkern"]={|
1219   |["bottom_left"] ={ { ["height"]=420, ["kern"]=80  }, { ["height"]=520,  ["kern"]=4   } },|
1220   |["bottom_right"]={ { ["height"]=0,   ["kern"]=48  } },|
1221   |["top_left"]    ={ { ["height"]=620, ["kern"]=0   }, { ["height"]=720,  ["kern"]=-80 } },|
1222   |["top_right"]   ={ { ["height"]=676, ["kern"]=115 }, { ["height"]=776,  ["kern"]=45  } },|
1223   |}|
1224 */
1225            lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(mathkern));
1226            lua_rawget(L, -2);
1227            if (lua_istable(L, -1)) {
1228	        store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
1229                store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
1230                store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
1231                store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
1232            }
1233            lua_pop(L, 1);
1234        }
1235        /* end of |has_math| */
1236        nk = count_hash_items(L, lua_key_index(kerns));
1237        if (nk > 0) {
1238            ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
1239            lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(kerns));
1240            lua_rawget(L, -2);
1241            if (lua_istable(L, -1)) {   /* there are kerns */
1242                ctr = 0;
1243                lua_pushnil(L);
1244                while (lua_next(L, -2) != 0) {
1245                    k = non_boundarychar;
1246                    if (lua_isnumber(L, -2)) {
1247                        k=(int)lua_tonumber(L, -2); /* adjacent char */
1248                        if (k < 0)
1249                            k = non_boundarychar;
1250                    } else if (lua_isstring(L, -2)) {
1251                        s = lua_tostring(L, -2);
1252                        if (lua_key_eq(s, right_boundary)) {
1253                            k = right_boundarychar;
1254                            if (!has_right_boundary(f))
1255                                set_right_boundary(f,
1256                                                   get_charinfo(f,
1257                                                                right_boundarychar));
1258                        }
1259                    }
1260                    j = lua_roundnumber(L, -1); /* movement */
1261                    if (k != non_boundarychar) {
1262                        set_kern_item(ckerns[ctr], k, j);
1263                        ctr++;
1264                    } else {
1265                        luatex_warn
1266                            ("lua-loaded font %s char [U+%X] has an invalid kern field!",
1267                             font_name(f), (int) i);
1268                    }
1269                    lua_pop(L, 1);
1270                }
1271                /* guard against empty tables */
1272                if (ctr > 0) {
1273                    set_kern_item(ckerns[ctr], end_kern, 0);
1274                    set_charinfo_kerns(co, ckerns);
1275                } else {
1276                    luatex_warn
1277                        ("lua-loaded font %s char [U+%X] has an invalid kerns field!",
1278                         font_name(f), (int) i);
1279                }
1280            }
1281            lua_pop(L, 1);
1282        }
1283
1284        /* packet commands */
1285        lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(commands));
1286        lua_rawget(L, -2);
1287        if (lua_istable(L, -1)) {
1288            lua_pushnil(L);     /* first key */
1289            if (lua_next(L, -2) != 0) {
1290                lua_pop(L, 2);
1291                read_char_packets(L, (int *) l_fonts, co, atsize);
1292            }
1293        }
1294        lua_pop(L, 1);
1295
1296        /* ligatures */
1297        nl = count_hash_items(L, lua_key_index(ligatures));
1298
1299        if (nl > 0) {
1300            cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
1301            lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(ligatures));
1302            lua_rawget(L, -2);
1303            if (lua_istable(L, -1)) {   /* do ligs */
1304                ctr = 0;
1305                lua_pushnil(L);
1306                while (lua_next(L, -2) != 0) {
1307                    k = non_boundarychar;
1308                    if (lua_isnumber(L, -2)) {
1309                        k=(int)lua_tonumber(L, -2); /* adjacent char */
1310                        if (k < 0) {
1311                            k = non_boundarychar;
1312                        }
1313                    } else if (lua_isstring(L, -2)) {
1314                        s = lua_tostring(L, -2);
1315                        if (lua_key_eq(s, right_boundary)) {
1316                            k = right_boundarychar;
1317                            if (!has_right_boundary(f))
1318                                set_right_boundary(f,
1319                                                   get_charinfo(f,
1320                                                                right_boundarychar));
1321                        }
1322                    }
1323                    r = -1;
1324                    if (lua_istable(L, -1)) {
1325                        r = lua_numeric_field_by_index(L, lua_key_index(char), -1);    /* ligature */
1326                    }
1327                    if (r != -1 && k != non_boundarychar) {
1328		        t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
1329		        set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k,
1330                                          r);
1331                        ctr++;
1332                    } else {
1333                        luatex_warn
1334                            ("lua-loaded font %s char [U+%X] has an invalid ligature field!",
1335                             font_name(f), (int) i);
1336                    }
1337                    lua_pop(L, 1);      /* iterator value */
1338                }
1339                /* guard against empty tables */
1340                if (ctr > 0) {
1341                    set_ligature_item(cligs[ctr], 0, end_ligature, 0);
1342                    set_charinfo_ligatures(co, cligs);
1343                } else {
1344                    luatex_warn
1345                        ("lua-loaded font %s char [U+%X] has an invalid ligatures field!",
1346                         font_name(f), (int) i);
1347                }
1348            }
1349            lua_pop(L, 1);      /* ligatures table */
1350        }
1351    }
1352}
1353
1354
1355
1356@ The caller has to fix the state of the lua stack when there is an error!
1357
1358@c
1359int font_from_lua(lua_State * L, int f)
1360{
1361    int i, n, r, t;
1362    int s_top;                  /* lua stack top */
1363    int bc;                     /* first char index */
1364    int ec;                     /* last char index */
1365    char *s;
1366    const char *ss;
1367    int *l_fonts = NULL;
1368    int save_ref ;
1369    boolean no_math = false;
1370
1371    /* will we save a cache of the luat table? */
1372
1373    save_ref = 1; /* we start with  ss = "yes" */
1374    ss = NULL;
1375    ss = n_string_field(L, lua_key_index(cache));
1376    if (lua_key_eq(ss, no))
1377        save_ref = -1;
1378    else if (lua_key_eq(ss, renew))
1379        save_ref = 0;
1380    /* n_string_field leaves a value on stack*/
1381    lua_pop(L,1);
1382
1383    /* the table is at stack index -1 */
1384    /*if (luaS_width_index == 0)
1385        init_font_string_pointers(L);
1386    */
1387
1388    s = n_string_field_copy(L,lua_key_index(area), "");
1389    set_font_area(f, s);
1390    s = n_string_field_copy(L, lua_key_index(filename), NULL);
1391    set_font_filename(f, s);
1392    s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
1393    set_font_encodingname(f, s);
1394
1395    s = n_string_field_copy(L, lua_key_index(name), NULL);
1396    set_font_name(f, s);
1397    s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
1398    set_font_fullname(f, s);
1399
1400    if (s == NULL) {
1401        luatex_fail("lua-loaded font [%d] has no name!", f);
1402        return false;
1403    }
1404    s = n_string_field_copy(L, lua_key_index(psname), NULL);
1405    set_font_psname(f, s);
1406
1407    i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
1408    set_font_units_per_em(f, i);
1409    i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
1410    set_font_dsize(f, i);
1411    i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
1412    set_font_size(f, i);
1413    set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
1414    i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
1415    set_font_natural_dir(f, i);
1416    i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
1417    set_font_encodingbytes(f, (char) i);
1418    i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
1419    set_font_tounicode(f, (char) i);
1420
1421    i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000);
1422    if (i < FONT_EXTEND_MIN)
1423        i = FONT_EXTEND_MIN;
1424    if (i > FONT_EXTEND_MAX)
1425        i = FONT_EXTEND_MAX;
1426    set_font_extend(f, i);
1427    i = lua_numeric_field_by_index(L,lua_key_index(slant), 0);
1428    if (i < FONT_SLANT_MIN)
1429        i = FONT_SLANT_MIN;
1430    if (i > FONT_SLANT_MAX)
1431        i = FONT_SLANT_MAX;
1432    set_font_slant(f, i);
1433
1434    i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), int_par(default_hyphen_char_code));
1435    set_hyphen_char(f, i);
1436    i = lua_numeric_field_by_index(L,lua_key_index(skewchar), int_par(default_skew_char_code));
1437    set_skew_char(f, i);
1438    i = n_boolean_field(L, lua_key_index(used), 0);
1439    set_font_used(f, (char) i);
1440
1441    s = n_string_field_copy(L, lua_key_index(attributes), NULL);
1442    if (s != NULL && strlen(s) > 0) {
1443        i = maketexstring(s);
1444        set_pdf_font_attr(f, i);
1445    }
1446    free(s);
1447
1448    i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
1449    set_font_type(f, i);
1450    i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
1451    set_font_format(f, i);
1452    i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings);
1453    set_font_embedding(f, i);
1454    if (font_encodingbytes(f) == 0 &&
1455        (font_format(f) == opentype_format
1456         || font_format(f) == truetype_format)) {
1457        set_font_encodingbytes(f, 2);
1458    }
1459
1460    /* now fetch the base fonts, if needed */
1461    n = count_hash_items(L, lua_key_index(fonts));
1462    if (n > 0) {
1463        l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
1464        memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
1465        lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(fonts));
1466        lua_rawget(L, -2);
1467        for (i = 1; i <= n; i++) {
1468            lua_rawgeti(L, -1, i);
1469            if (lua_istable(L, -1)) {
1470		lua_key_rawgeti(id);
1471                if (lua_isnumber(L, -1)) {
1472                    l_fonts[i]=(int)lua_tonumber(L, -1);
1473                    lua_pop(L, 2);      /* pop id  and entry */
1474                    continue;
1475                }
1476                lua_pop(L, 1);  /* pop id */
1477            };
1478            ss = NULL;
1479            if (lua_istable(L, -1)) {
1480                /* lua_getfield(L, -1, "name"); */
1481                /* if (lua_isstring(L, -1)) { */
1482                /*     ss = lua_tostring(L, -1); */
1483                /* } */
1484                /* lua_pop(L, 1);  /\* pop name *\/ */
1485		ss = n_string_field(L, lua_key_index(name));
1486                /* string is anchored */
1487                lua_pop(L,1);
1488            }
1489            if (ss != NULL) {
1490                /* lua_getfield(L, -1, "size"); */
1491                /* t = (lua_isnumber(L, -1) ? lua_roundnumber(L, -1) : -1000); */
1492                /* lua_pop(L, 1); */
1493	        t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
1494                /* TODO: the stack is messed up, otherwise this
1495                 * explicit resizing would not be needed
1496                 */
1497                s_top = lua_gettop(L);
1498                if (strcmp(font_name(f), ss) == 0)
1499                    l_fonts[i] = f;
1500                else
1501                    l_fonts[i] = find_font_id(ss, t);
1502                lua_settop(L, s_top);
1503            } else {
1504                luatex_fail("Invalid local font in font %s!\n", font_name(f));
1505            }
1506            lua_pop(L, 1);      /* pop list entry */
1507        }
1508        lua_pop(L, 1);          /* pop list entry */
1509    } else {
1510        if (font_type(f) == virtual_font_type) {
1511            luatex_fail("Invalid local fonts in font %s!\n", font_name(f));
1512        } else {
1513            l_fonts = xmalloc(3 * sizeof(int));
1514            l_fonts[0] = 0;
1515            l_fonts[1] = f;
1516            l_fonts[2] = 0;
1517        }
1518    }
1519
1520    /* parameters */
1521    no_math = n_boolean_field(L, lua_key_index(nomath), 0);
1522    read_lua_parameters(L, f);
1523    if (!no_math) {
1524        read_lua_math_parameters(L, f);
1525    }
1526    read_lua_cidinfo(L, f);
1527
1528    /* characters */
1529    //lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(characters));lua_rawget(L, -2);
1530    lua_key_rawgeti(characters);
1531     /*lua_getfield(L, -1, "characters");*/
1532    if (lua_istable(L, -1)) {
1533        /* find the array size values */
1534        int num = 0;            /* number of charinfo's to add */
1535        ec = 0;
1536        bc = -1;
1537        lua_pushnil(L);         /* first key */
1538        while (lua_next(L, -2) != 0) {
1539            if (lua_isnumber(L, -2)) {
1540                i = (int) lua_tointeger(L, -2);
1541                if (i >= 0) {
1542                    if (lua_istable(L, -1)) {
1543                        num++;
1544                        if (i > ec)
1545                            ec = i;
1546                        if (bc < 0)
1547                            bc = i;
1548                        if (bc >= 0 && i < bc)
1549                            bc = i;
1550                    }
1551                }
1552            }
1553            lua_pop(L, 1);
1554        }
1555        if (bc != -1) {
1556#if 0
1557            fprintf(stdout,"defined a font at %d with %d-%d\n",f,bc,ec);
1558#endif
1559            font_malloc_charinfo(f, num);
1560            set_font_bc(f, bc);
1561            set_font_ec(f, ec);
1562            lua_pushnil(L);     /* first key */
1563            while (lua_next(L, -2) != 0) {
1564                if (lua_isnumber(L, -2)) {
1565                    i=(int)lua_tonumber(L, -2);
1566                    if (i >= 0) {
1567                        font_char_from_lua(L, f, i, l_fonts, !no_math);
1568                    }
1569                } else if (lua_isstring(L, -2)) {
1570                    const char *ss1 = lua_tostring(L, -2);
1571                    if (lua_key_eq(ss1, left_boundary)) {
1572                        font_char_from_lua(L, f, left_boundarychar, l_fonts,
1573                                           !no_math);
1574                    } else if (lua_key_eq(ss1, right_boundary)) {
1575                        font_char_from_lua(L, f, right_boundarychar, l_fonts,
1576                                           !no_math);
1577                    }
1578                }
1579                lua_pop(L, 1);
1580            }
1581            lua_pop(L, 1);
1582
1583            /* handle font expansion last: the |copy_font| routine is called eventually,
1584               and that needs to know |bc| and |ec|. */
1585            if (font_type(f) != virtual_font_type) {
1586	        int fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0);
1587                if (fstep < 0)
1588                    fstep = 0;
1589                if (fstep > 100)
1590                    fstep = 100;
1591                if (fstep != 0) {
1592		  int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
1593		  int fstretch =lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
1594		  int fexpand = n_boolean_field(L, lua_key_index(auto_expand), 0);
1595                    if (fshrink < 0)
1596                        fshrink = 0;
1597                    if (fshrink > 500)
1598                        fshrink = 500;
1599                    fshrink -= (fshrink % fstep);
1600                    if (fshrink < 0)
1601                        fshrink = 0;
1602                    if (fstretch < 0)
1603                        fstretch = 0;
1604                    if (fstretch > 1000)
1605                        fstretch = 1000;
1606                    fstretch -= (fstretch % fstep);
1607                    if (fstretch < 0)
1608                        fstretch = 0;
1609                    set_expand_params(f, fexpand, fstretch, fshrink, fstep);
1610                }
1611            }
1612
1613        } else {                /* jikes, no characters */
1614            luatex_warn("lua-loaded font [%d] (%s) has no characters!", f,
1615                        font_name(f));
1616        }
1617
1618        if (save_ref > 0) {
1619            r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
1620            set_font_cache_id(f, r);
1621        } else {
1622            lua_pop(L, 1);
1623            set_font_cache_id(f, save_ref);
1624        }
1625    } else {                    /* jikes, no characters */
1626        luatex_warn("lua-loaded font [%d] (%s) has no character table!", f,
1627                    font_name(f));
1628    }
1629
1630    if (l_fonts != NULL)
1631        free(l_fonts);
1632    return true;
1633}
1634
1635
1636
1637@* Ligaturing.
1638
1639@c
1640#define assert_disc(a) \
1641  assert(pre_break(a)!=null); /* expect |head_node| */ \
1642  assert(type(pre_break(a))==nesting_node);       \
1643  assert((vlink_pre_break(a)==null && tlink_pre_break(a)==null) || \
1644         tail_of_list(vlink_pre_break(a))==tlink_pre_break(a)); \
1645  assert(post_break(a)!=null); /* expect |head_node| */ \
1646  assert(type(post_break(a))==nesting_node);            \
1647  assert((vlink_post_break(a)==null && tlink_post_break(a)==null) || \
1648         tail_of_list(vlink_post_break(a))==tlink_post_break(a)); \
1649  assert(no_break(a)!=null); /* expect |head_node| */   \
1650  assert(type(no_break(a))==nesting_node);            \
1651  assert((vlink_no_break(a)==null && tlink_no_break(a)==null) || \
1652         tail_of_list(vlink_no_break(a))==tlink_no_break(a));
1653
1654static void nesting_append(halfword nest1, halfword newn)
1655{
1656    halfword tail = tlink(nest1);
1657    assert(alink(nest1) == null);
1658    assert(vlink(newn) == null);
1659    assert(alink(newn) == null);
1660    if (tail == null) {
1661        assert(vlink(nest1) == null);
1662        couple_nodes(nest1, newn);
1663    } else {
1664        assert(vlink(tail) == null);
1665        assert(tail_of_list(vlink(nest1)) == tail);
1666        couple_nodes(tail, newn);
1667    }
1668    tlink(nest1) = newn;
1669}
1670
1671
1672static void nesting_prepend(halfword nest1, halfword newn)
1673{
1674    halfword head = vlink(nest1);
1675    assert(alink(nest1) == null);
1676    assert(vlink(newn) == null);
1677    assert(alink(newn) == null);
1678    couple_nodes(nest1, newn);
1679    if (head == null) {
1680        assert(tlink(nest1) == null);
1681        tlink(nest1) = newn;
1682    } else {
1683        assert(alink(head) == nest1);
1684        assert(tail_of_list(head) == tlink(nest1));
1685        couple_nodes(newn, head);
1686    }
1687}
1688
1689
1690static void nesting_prepend_list(halfword nest1, halfword newn)
1691{
1692    halfword head = vlink(nest1);
1693    assert(alink(nest1) == null);
1694    assert(alink(newn) == null);
1695    couple_nodes(nest1, newn);
1696    if (head == null) {
1697        assert(tlink(nest1) == null);
1698        tlink(nest1) = tail_of_list(newn);
1699    } else {
1700        halfword tail = tail_of_list(newn);
1701        assert(alink(head) == nest1);
1702        assert(tail_of_list(head) == tlink(nest1));
1703        couple_nodes(tail, head);
1704    }
1705}
1706
1707
1708static int test_ligature(liginfo * lig, halfword left, halfword right)
1709{
1710    if (type(left) != glyph_node)
1711        return 0;
1712    assert(type(right) == glyph_node);
1713    if (font(left) != font(right))
1714        return 0;
1715    if (is_ghost(left) || is_ghost(right))
1716        return 0;
1717    *lig = get_ligature(font(left), character(left), character(right));
1718    if (is_valid_ligature(*lig)) {
1719        return 1;
1720    }
1721    return 0;
1722}
1723
1724
1725static int try_ligature(halfword * frst, halfword fwd)
1726{
1727    halfword cur = *frst;
1728    liginfo lig;
1729    if (test_ligature(&lig, cur, fwd)) {
1730        int move_after = (lig_type(lig) & 0x0C) >> 2;
1731        int keep_right = ((lig_type(lig) & 0x01) != 0);
1732        int keep_left = ((lig_type(lig) & 0x02) != 0);
1733        halfword newgl = raw_glyph_node();
1734        font(newgl) = font(cur);
1735        character(newgl) = lig_replacement(lig);
1736        set_is_ligature(newgl);
1737
1738        /* below might not be correct in contrived border case.
1739           but we use it only for debugging, so ... */
1740        if (character(cur) < 0) {
1741            set_is_leftboundary(newgl);
1742        }
1743        if (character(fwd) < 0) {
1744            set_is_rightboundary(newgl);
1745        }
1746        if (character(cur) < 0) {
1747            if (character(fwd) < 0) {
1748                build_attribute_list(newgl);
1749            } else {
1750                add_node_attr_ref(node_attr(fwd));
1751                node_attr(newgl) = node_attr(fwd);
1752            }
1753        } else {
1754            add_node_attr_ref(node_attr(cur));
1755            node_attr(newgl) = node_attr(cur);
1756        }
1757
1758        /* TODO/FIXME if this ligature is consists of another ligature
1759         we should add it's |lig_ptr| to the new glyphs |lig_ptr| (and
1760         cleanup the no longer needed node) LOW PRIORITY */
1761        /* left side */
1762        if (keep_left) {
1763            halfword new_first = copy_node(cur);
1764            lig_ptr(newgl) = new_first;
1765            couple_nodes(cur, newgl);
1766            if (move_after) {
1767                move_after--;
1768                cur = newgl;
1769            }
1770        } else {
1771            halfword prev = alink(cur);
1772            uncouple_node(cur);
1773            lig_ptr(newgl) = cur;
1774            assert(prev != null);
1775            couple_nodes(prev, newgl);
1776            cur = newgl;        /* as cur has disappeared */
1777        }
1778        /* right side */
1779        if (keep_right) {
1780            halfword new_second = copy_node(fwd);
1781            /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
1782            couple_nodes(lig_ptr(newgl), new_second);
1783            couple_nodes(newgl, fwd);
1784            if (move_after) {
1785                move_after--;
1786                cur = fwd;
1787            }
1788        } else {
1789            halfword next = vlink(fwd);
1790            uncouple_node(fwd);
1791            /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
1792            couple_nodes(lig_ptr(newgl), fwd);
1793            if (next != null) {
1794                couple_nodes(newgl, next);
1795            }
1796        }
1797
1798        /* check and return */
1799        *frst = cur;
1800        return 1;
1801    }
1802    return 0;
1803}
1804
1805
1806@ there shouldn't be any ligatures here - we only add them at the end of
1807 |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing \.{DISC-1}
1808 (we continue with \.{DISC-1}'s |post_| and |no_break|.
1809
1810@c
1811static halfword handle_lig_nest(halfword root, halfword cur)
1812{
1813    if (cur == null)
1814        return root;
1815    while (vlink(cur) != null) {
1816        halfword fwd = vlink(cur);
1817        if (type(cur) == glyph_node && type(fwd) == glyph_node &&
1818            font(cur) == font(fwd) && try_ligature(&cur, fwd))
1819            continue;
1820        cur = vlink(cur);
1821        assert(vlink(alink(cur)) == cur);
1822    }
1823    tlink(root) = cur;
1824    return root;
1825}
1826
1827
1828static halfword handle_lig_word(halfword cur)
1829{
1830    halfword right = null;
1831    if (type(cur) == whatsit_node && subtype(cur) == cancel_boundary_node) {
1832        halfword prev = alink(cur);
1833        halfword fwd = vlink(cur);
1834        /* no need to uncouple |cur|, it is freed */
1835        flush_node(cur);
1836        if (fwd == null) {
1837            vlink(prev) = fwd;
1838            return prev;
1839        }
1840        couple_nodes(prev, fwd);
1841        if (type(fwd) != glyph_node)
1842            return prev;
1843        cur = fwd;
1844    } else if (has_left_boundary(font(cur))) {
1845        halfword prev = alink(cur);
1846        halfword p = new_glyph(font(cur), left_boundarychar);
1847        couple_nodes(prev, p);
1848        couple_nodes(p, cur);
1849        cur = p;
1850    }
1851    if (has_right_boundary(font(cur))) {
1852        right = new_glyph(font(cur), right_boundarychar);
1853    }
1854    while (1) {
1855        /* A glyph followed by ... */
1856        if (type(cur) == glyph_node) {
1857            halfword fwd = vlink(cur);
1858            if (fwd == null) {  /* last character of paragraph */
1859                if (right == null)
1860                    break;
1861                /* \.{--\\par} prohibits use of |couple_nodes| here */
1862                try_couple_nodes(cur, right);
1863                right = null;
1864                continue;
1865            }
1866            assert(alink(fwd) == cur);
1867            if (type(fwd) == glyph_node) {      /* |GLYPH - GLYPH| */
1868                if (font(cur) != font(fwd))
1869                    break;
1870                if (try_ligature(&cur, fwd))
1871                    continue;
1872            } else if (type(fwd) == disc_node) {        /* |GLYPH - DISC| */
1873
1874                /* if  \.{a{bx}{}{y}} and \.{a+b=>B} convert to \.{{Bx}{}{ay}} */
1875                halfword pre = vlink_pre_break(fwd);
1876                halfword nob = vlink_no_break(fwd);
1877                halfword next, tail;
1878                liginfo lig;
1879                assert_disc(fwd);
1880                /* Check on: a{b?}{?}{?} and a+b=>B : {B?}{?}{a?} */
1881                /* Check on: a{?}{?}{b?} and a+b=>B : {a?}{?}{B?} */
1882                if ((pre != null && type(pre) == glyph_node
1883                     && test_ligature(&lig, cur, pre))
1884                    || (nob != null && type(nob) == glyph_node
1885                        && test_ligature(&lig, cur, nob))) {
1886                    /* move cur from before disc, to skipped part */
1887                    halfword prev = alink(cur);
1888                    assert(vlink(prev) == cur);
1889                    uncouple_node(cur);
1890                    couple_nodes(prev, fwd);
1891                    nesting_prepend(no_break(fwd), cur);
1892                    /* now ligature the |pre_break| */
1893                    nesting_prepend(pre_break(fwd), copy_node(cur));
1894                    /* As we have removed cur, we need to start again ... */
1895                    cur = prev;
1896                }
1897                /* Check on: a{?}{?}{}b and a+b=>B : {a?}{?b}{B} */
1898                next = vlink(fwd);
1899                if (nob == null && next != null && type(next) == glyph_node
1900                    && test_ligature(&lig, cur, next)) {
1901                    /* move |cur| from before |disc| to |no_break| part */
1902                    halfword prev = alink(cur);
1903                    assert(alink(next) == fwd);
1904                    assert(vlink(prev) == cur);
1905                    uncouple_node(cur);
1906                    couple_nodes(prev, fwd);
1907                    couple_nodes(no_break(fwd), cur);   /* we {\it know\/} it's empty */
1908                    /* now copy cur the |pre_break| */
1909                    nesting_prepend(pre_break(fwd), copy_node(cur));
1910                    /* move next from after disc to |no_break| part */
1911                    tail = vlink(next);
1912                    uncouple_node(next);
1913                    try_couple_nodes(fwd, tail);
1914                    couple_nodes(cur, next);    /* we {\it know\/} this works */
1915                    tlink(no_break(fwd)) = next;        /* and make sure the list is correct */
1916                    /* now copy next to the |post_break| */
1917                    nesting_append(post_break(fwd), copy_node(next));
1918                    /* As we have removed cur, we need to start again ... */
1919                    cur = prev;
1920                }
1921                /* we are finished with the |pre_break| */
1922                handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd));
1923            } else if (type(fwd) == whatsit_node
1924                       && subtype(fwd) == cancel_boundary_node) {
1925                halfword next = vlink(fwd);
1926                try_couple_nodes(cur, next);
1927                flush_node(fwd);
1928                if (right != null) {
1929                    flush_node(right);  /* Shame, didn't need it */
1930                    /* no need to reset |right|, we're going to leave the loop anyway */
1931                }
1932                break;
1933            } else {            /* fwd is something unknown */
1934                if (right == null)
1935                    break;
1936                couple_nodes(cur, right);
1937                couple_nodes(right, fwd);
1938                right = null;
1939                continue;
1940            }
1941            /* A discretionary followed by ... */
1942        } else if (type(cur) == disc_node) {
1943
1944            assert_disc(cur);
1945            /* If \.{{?}{x}{?}} or \.{{?}{?}{y}} then ... */
1946            if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
1947                halfword prev = 0;
1948                halfword fwd;
1949                liginfo lig;
1950                if (subtype(cur) == select_disc) {
1951                    prev = alink(cur);
1952                    assert(type(prev) == disc_node
1953                           && subtype(prev) == init_disc);
1954                    if (vlink_post_break(cur) != null)
1955                        handle_lig_nest(post_break(prev),
1956                                        vlink_post_break(prev));
1957                    if (vlink_no_break(cur) != null)
1958                        handle_lig_nest(no_break(prev), vlink_no_break(prev));
1959                }
1960                if (vlink_post_break(cur) != null)
1961                    handle_lig_nest(post_break(cur), vlink_post_break(cur));
1962                if (vlink_no_break(cur) != null)
1963                    handle_lig_nest(no_break(cur), vlink_no_break(cur));
1964                while ((fwd = vlink(cur)) != null) {
1965                    halfword nob, pst, next;
1966                    if (type(fwd) != glyph_node)
1967                        break;
1968                    if (subtype(cur) != select_disc) {
1969                        nob = tlink_no_break(cur);
1970                        pst = tlink_post_break(cur);
1971                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
1972                            (pst == null || !test_ligature(&lig, pst, fwd)))
1973                            break;
1974                        nesting_append(no_break(cur), copy_node(fwd));
1975                        handle_lig_nest(no_break(cur), nob);
1976                    } else {
1977                        int dobreak = 0;
1978                        nob = tlink_no_break(prev);
1979                        pst = tlink_post_break(prev);
1980                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
1981                            (pst == null || !test_ligature(&lig, pst, fwd)))
1982                            dobreak = 1;
1983                        if (!dobreak) {
1984                            nesting_append(no_break(prev), copy_node(fwd));
1985                            handle_lig_nest(no_break(prev), nob);
1986                            nesting_append(post_break(prev), copy_node(fwd));
1987                            handle_lig_nest(post_break(prev), pst);
1988                        }
1989                        dobreak = 0;
1990                        nob = tlink_no_break(cur);
1991                        pst = tlink_post_break(cur);
1992                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
1993                            (pst == null || !test_ligature(&lig, pst, fwd)))
1994                            dobreak = 1;
1995                        if (!dobreak) {
1996                            nesting_append(no_break(cur), copy_node(fwd));
1997                            handle_lig_nest(no_break(cur), nob);
1998                        }
1999                        if (dobreak)
2000                            break;
2001                    }
2002                    next = vlink(fwd);
2003                    uncouple_node(fwd);
2004                    try_couple_nodes(cur, next);
2005                    nesting_append(post_break(cur), fwd);
2006                    handle_lig_nest(post_break(cur), pst);
2007                }
2008                if (fwd != null && type(fwd) == disc_node) {
2009                    halfword next = vlink(fwd);
2010                    if (vlink_no_break(fwd) == null &&
2011                        vlink_post_break(fwd) == null &&
2012                        next != null &&
2013                        type(next) == glyph_node &&
2014                        ((tlink_post_break(cur) != null &&
2015                          test_ligature(&lig, tlink_post_break(cur), next)) ||
2016                         (tlink_no_break(cur) != null &&
2017                          test_ligature(&lig, tlink_no_break(cur), next)))) {
2018                        /* Building an |init_disc| followed by a |select_disc|
2019                          \.{{a-}{b}{AB} {-}{}{}} 'c'
2020                         */
2021                        /* is it tail necessary ? */
2022                        halfword last1 = vlink(next), tail ;
2023                        uncouple_node(next);
2024                        try_couple_nodes(fwd, last1);
2025                        /* \.{{a-}{b}{AB} {-}{c}{}} */
2026                        nesting_append(post_break(fwd), copy_node(next));
2027                        /* \.{{a-}{b}{AB} {-}{c}{-}} */
2028                        if (vlink_no_break(cur) != null) {
2029                            nesting_prepend(no_break(fwd),
2030                                            copy_node(vlink_pre_break(fwd)));
2031                        }
2032                        /* \.{{a-}{b}{AB} {b-}{c}{-}} */
2033                        if (vlink_post_break(cur) != null)
2034                            nesting_prepend_list(pre_break(fwd),
2035                                                 copy_node_list(vlink_post_break
2036                                                                (cur)));
2037                        /* \.{{a-}{b}{AB} {b-}{c}{AB-}} */
2038                        if (vlink_no_break(cur) != null) {
2039                            nesting_prepend_list(no_break(fwd),
2040                                                 copy_node_list(vlink_no_break
2041                                                                (cur)));
2042                        }
2043                        /* \.{{a-}{b}{ABC} {b-}{c}{AB-}} */
2044                        tail = tlink_no_break(cur);
2045                        nesting_append(no_break(cur), copy_node(next));
2046                        handle_lig_nest(no_break(cur), tail);
2047                        /* \.{{a-}{BC}{ABC} {b-}{c}{AB-}} */
2048                        tail = tlink_post_break(cur);
2049                        nesting_append(post_break(cur), next);
2050                        handle_lig_nest(post_break(cur), tail);
2051                        /* and set the subtypes */
2052                        subtype(cur) = init_disc;
2053                        subtype(fwd) = select_disc;
2054                    }
2055                }
2056            }
2057
2058        } else {                /* NO GLYPH NOR DISC */
2059            return cur;
2060        }
2061        /* step-to-next-node */
2062        {
2063            halfword prev = cur;
2064            /* \.{--\\par} allows |vlink(cur)| to be null */
2065            cur = vlink(cur);
2066            if (cur != null) {
2067                assert(alink(cur) == prev);
2068            }
2069        }
2070    }
2071
2072    return cur;
2073}
2074
2075@ Return value is the new tail, head should be a dummy
2076
2077@c
2078halfword handle_ligaturing(halfword head, halfword tail)
2079{
2080    halfword save_tail1;         /* trick to allow explicit |node==null| tests */
2081    halfword cur, prev;
2082
2083    if (vlink(head) == null)
2084        return tail;
2085    save_tail1 = vlink(tail);
2086    vlink(tail) = null;
2087
2088    /* |if (fix_node_lists)| */
2089    fix_node_list(head);
2090
2091    prev = head;
2092    cur = vlink(prev);
2093
2094    while (cur != null) {
2095        if (type(cur) == glyph_node ||
2096            (type(cur) == whatsit_node
2097             && subtype(cur) == cancel_boundary_node)) {
2098            cur = handle_lig_word(cur);
2099        }
2100        prev = cur;
2101        cur = vlink(cur);
2102        assert(cur == null || alink(cur) == prev);
2103    }
2104    if (prev == null)
2105        prev = tail;
2106
2107    if (valid_node(save_tail1)) {
2108        try_couple_nodes(prev, save_tail1);
2109    }
2110    return prev;
2111}
2112
2113
2114@* Kerning.
2115
2116@c
2117static void add_kern_before(halfword left, halfword right)
2118{
2119    if ((!is_rightghost(right)) &&
2120        font(left) == font(right) && has_kern(font(left), character(left))) {
2121        int k = raw_get_kern(font(left), character(left), character(right));
2122        if (k != 0) {
2123            halfword kern = new_kern(k);
2124            halfword prev = alink(right);
2125            assert(vlink(prev) == right);
2126            couple_nodes(prev, kern);
2127            couple_nodes(kern, right);
2128            /* update the attribute list (inherit from left) */
2129            delete_attribute_ref(node_attr(kern));
2130            add_node_attr_ref(node_attr(left));
2131            node_attr(kern) = node_attr(left);
2132        }
2133    }
2134}
2135
2136
2137static void add_kern_after(halfword left, halfword right, halfword aft)
2138{
2139    if ((!is_rightghost(right)) &&
2140        font(left) == font(right) && has_kern(font(left), character(left))) {
2141        int k = raw_get_kern(font(left), character(left), character(right));
2142        if (k != 0) {
2143            halfword kern = new_kern(k);
2144            halfword next = vlink(aft);
2145            assert(next == null || alink(next) == aft);
2146            couple_nodes(aft, kern);
2147            try_couple_nodes(kern, next);
2148            /* update the attribute list (inherit from left == aft) */
2149            delete_attribute_ref(node_attr(kern));
2150            add_node_attr_ref(node_attr(aft));
2151            node_attr(kern) = node_attr(aft);
2152        }
2153    }
2154}
2155
2156
2157static void
2158do_handle_kerning(halfword root, halfword init_left, halfword init_right)
2159{
2160    halfword cur = vlink(root);
2161    halfword left = null;
2162    assert(init_left == null || type(init_left) == glyph_node);
2163    assert(init_right == null || type(init_right) == glyph_node);
2164    if (cur == null) {
2165        if (init_left != null && init_right != null) {
2166            add_kern_after(init_left, init_right, root);
2167            tlink(root) = vlink(root);
2168        }
2169        return;
2170    }
2171    if (type(cur) == glyph_node) {
2172        set_is_glyph(cur);
2173        if (init_left != null)
2174            add_kern_before(init_left, cur);
2175        left = cur;
2176    }
2177    while ((cur = vlink(cur)) != null) {
2178        if (type(cur) == glyph_node) {
2179            set_is_glyph(cur);
2180            if (left != null) {
2181                add_kern_before(left, cur);
2182                if (character(left) < 0 || is_ghost(left)) {
2183                    halfword prev = alink(left);
2184                    couple_nodes(prev, cur);
2185                    flush_node(left);
2186                }
2187            }
2188            left = cur;
2189        } else {
2190            if (type(cur) == disc_node) {
2191                halfword right =
2192                    type(vlink(cur)) == glyph_node ? vlink(cur) : null;
2193                do_handle_kerning(pre_break(cur), left, null);
2194                do_handle_kerning(post_break(cur), null, right);
2195                if (vlink_post_break(cur) != null)
2196                    tlink_post_break(cur) = tail_of_list(vlink_post_break(cur));
2197                do_handle_kerning(no_break(cur), left, right);
2198                if (vlink_no_break(cur) != null)
2199                    tlink_no_break(cur) = tail_of_list(vlink_no_break(cur));    /* needed? */
2200            }
2201            if (left != null) {
2202                if (character(left) < 0 || is_ghost(left)) {
2203                    halfword prev = alink(left);
2204                    couple_nodes(prev, cur);
2205                    flush_node(left);
2206                }
2207                left = null;
2208            }
2209        }
2210    }
2211    if (left != null) {
2212        if (init_right != null)
2213            add_kern_after(left, init_right, left);
2214        if (character(left) < 0 || is_ghost(left)) {
2215            halfword prev = alink(left);
2216            halfword next = vlink(left);
2217            if (next != null) {
2218                couple_nodes(prev, next);
2219                tlink(root) = next;
2220                assert(vlink(next) == null);
2221                assert(type(next) == kern_node);
2222            } else if (prev != root) {
2223                vlink(prev) = null;
2224                tlink(root) = prev;
2225            } else {
2226                vlink(root) = null;
2227                tlink(root) = null;
2228            }
2229            flush_node(left);
2230        }
2231    }
2232}
2233
2234
2235halfword handle_kerning(halfword head, halfword tail)
2236{
2237    halfword save_link;
2238    save_link = vlink(tail);
2239    vlink(tail) = null;
2240    tlink(head) = tail;
2241    do_handle_kerning(head, null, null);
2242    tail = tlink(head);
2243    if (valid_node(save_link)) {
2244        try_couple_nodes(tail, save_link);
2245    }
2246    return tail;
2247}
2248
2249@* ligaturing and kerning : lua-interface.
2250
2251@c
2252static halfword
2253run_lua_ligkern_callback(halfword head, halfword tail, int callback_id)
2254{
2255    lua_State *L = Luas;
2256    int i;
2257    int top = lua_gettop(L);
2258    if (!get_callback(L, callback_id)) {
2259        lua_pop(L, 2);
2260        return tail;
2261    }
2262    nodelist_to_lua(L, head);
2263    nodelist_to_lua(L, tail);
2264    if ((i=lua_pcall(L, 2, 0, 0)) != 0) {
2265        luatex_error(L, (i == LUA_ERRRUN ? 0 : 1));
2266        return tail;
2267    }
2268    /* next two lines disabled to be compatible with the manual */
2269#if 0
2270    tail = nodelist_from_lua(L);
2271    if (fix_node_lists)
2272#endif
2273        fix_node_list(head);
2274    lua_settop(L, top);
2275    return tail;
2276}
2277
2278
2279halfword new_ligkern(halfword head, halfword tail)
2280{
2281    int callback_id = 0;
2282
2283    assert(head != null);
2284    if (vlink(head) == null)
2285        return tail;
2286
2287    callback_id = callback_defined(ligaturing_callback);
2288    if (callback_id > 0) {
2289        tail = run_lua_ligkern_callback(head, tail, callback_id);
2290        if (tail == null)
2291            tail = tail_of_list(head);
2292    } else if (callback_id == 0) {
2293        tail = handle_ligaturing(head, tail);
2294    }
2295
2296    callback_id = callback_defined(kerning_callback);
2297    if (callback_id > 0) {
2298        tail = run_lua_ligkern_callback(head, tail, callback_id);
2299        if (tail == null)
2300            tail = tail_of_list(head);
2301    } else if (callback_id == 0) {
2302        halfword nest1 = new_node(nesting_node, 1);
2303        halfword cur = vlink(head);
2304        halfword aft = vlink(tail);
2305        couple_nodes(nest1, cur);
2306        tlink(nest1) = tail;
2307        vlink(tail) = null;
2308        do_handle_kerning(nest1, null, null);
2309        couple_nodes(head, vlink(nest1));
2310        tail = tlink(nest1);
2311        try_couple_nodes(tail, aft);
2312        flush_node(nest1);
2313    }
2314    return tail;
2315}
2316