1 /* luafflib.c
2 
3    Copyright 2007-2010 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 /**
21 *  @desc Support interface for fontforge 20070607
22 *  @version  1.0
23 *  @author Taco Hoekwater
24 */
25 
26 #include "pfaedit.h"
27 #include "ustring.h"
28 #include "lib/lib.h"            /* web2c's lib, for recorder_record_input */
29 
30 #include <stdio.h>
31 #include <lua.h>
32 #ifdef LuajitTeX
33 #include <lua/lauxlib_bridge.h>
34 #else
35 #include <lauxlib.h>
36 #endif
37 #include <locale.h>
38 
39 
40 extern char **gww_errors;
41 extern int gww_error_count;
42 extern void gwwv_errors_free(void);
43 extern struct ui_interface luaui_interface;
44 
45 extern int readbinfile(FILE * f, unsigned char **b, int *s);
46 
47 #define FONT_METATABLE "fontloader.splinefont"
48 #define FONT_SUBFONT_METATABLE "fontloader.splinefont.subfont"
49 #define FONT_GLYPHS_METATABLE "fontloader.splinefont.glyphs"
50 #define FONT_GLYPH_METATABLE "fontloader.splinefont.glyph"
51 
52 #define LUA_OTF_VERSION "0.3"
53 
54 static char *possub_type_enum[] = {
55     "null", "position", "pair", "substitution",
56     "alternate", "multiple", "ligature", "lcaret",
57     "kerning", "vkerning", "anchors", "contextpos",
58     "contextsub", "chainpos", "chainsub", "reversesub",
59     "max", "kernback", "vkernback", NULL
60 };
61 
62 #define LAST_POSSUB_TYPE_ENUM 18
63 
64 #define eight_nulls() NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
65 
66 static char *otf_lookup_type_enum[] = {
67     "gsub_start", "gsub_single", "gsub_multiple", "gsub_alternate",
68     "gsub_ligature", "gsub_context", "gsub_contextchain", NULL,
69     "gsub_reversecontextchain", NULL, NULL, NULL, NULL, NULL, NULL, NULL,       /*0x00F */
70     eight_nulls(), eight_nulls(),
71     eight_nulls(), eight_nulls(),
72     eight_nulls(), eight_nulls(),
73     eight_nulls(), eight_nulls(),
74     eight_nulls(), eight_nulls(),
75     eight_nulls(), eight_nulls(),
76     eight_nulls(), eight_nulls(),
77     eight_nulls(), eight_nulls(),
78     eight_nulls(), eight_nulls(),
79     eight_nulls(), eight_nulls(),
80     eight_nulls(), eight_nulls(),
81     eight_nulls(), eight_nulls(),
82     eight_nulls(), eight_nulls(),
83     eight_nulls(), eight_nulls(),
84     eight_nulls(), eight_nulls(),
85     "gpos_start", "gpos_single", "gpos_pair", "gpos_cursive",
86     "gpos_mark2base", "gpos_mark2ligature", "gpos_mark2mark", "gpos_context",
87     "gpos_contextchain", NULL, NULL, NULL, NULL, NULL, NULL, NULL,      /* 0x10F */
88     eight_nulls(), eight_nulls(),
89     eight_nulls(), eight_nulls(),
90     eight_nulls(), eight_nulls(),
91     eight_nulls(), eight_nulls(),
92     eight_nulls(), eight_nulls(),
93     eight_nulls(), eight_nulls(),
94     eight_nulls(), eight_nulls(),
95     eight_nulls(), eight_nulls(),
96     eight_nulls(), eight_nulls(),
97     eight_nulls(), eight_nulls(),
98     eight_nulls(), eight_nulls(),
99     eight_nulls(), eight_nulls(),
100     eight_nulls(), eight_nulls(),
101     eight_nulls(), eight_nulls(),
102     eight_nulls(), eight_nulls(),
103 };
104 
105 
106 static char *anchor_type_enum[] = {
107     "mark", "basechar", "baselig", "basemark", "centry", "cexit", "max", NULL
108 };
109 
110 #define MAX_ANCHOR_TYPE 7
111 
112 static char *anchorclass_type_enum[] = {
113     "mark", "mkmk", "curs", "mklg", NULL
114 };
115 
116 static char *glyph_class_enum[] = {
117     "automatic", "none", "base", "ligature", "mark", "component", NULL
118 };
119 
120 static char *ttfnames_enum[ttf_namemax] = {
121     "copyright", "family", "subfamily", "uniqueid",
122     "fullname", "version", "postscriptname", "trademark",
123     "manufacturer", "designer", "descriptor", "venderurl",
124     "designerurl", "license", "licenseurl", "idontknow",
125     "preffamilyname", "prefmodifiers", "compatfull", "sampletext",
126     "cidfindfontname", "wwsfamily", "wwssubfamily"
127 };
128 
129 static char *fpossub_format_enum[] = {
130     "glyphs", "class", "coverage", "reversecoverage", NULL
131 };
132 
133 static char *tex_type_enum[4] = { "unset", "text", "math", "mathext" };
134 
135 /* has an offset of 1, ui_none = 0. */
136 static char *uni_interp_enum[9] = {
137     "unset", "none", "adobe", "greek", "japanese",
138     "trad_chinese", "simp_chinese", "korean", "ams"
139 };
140 
141 #define check_isfont(L,b) (SplineFont **)luaL_checkudata(L,b,FONT_METATABLE)
142 #define check_isglyph(L,b) (struct splinechar **)luaL_checkudata(L,b,FONT_GLYPH_METATABLE)
143 
144 void handle_generic_pst(lua_State * L, struct generic_pst *pst);        /* forward */
145 void handle_generic_fpst(lua_State * L, struct generic_fpst *fpst);     /* forward */
146 void handle_kernclass(lua_State * L, struct kernclass *kerns, const char *name);
147 void handle_anchorclass(lua_State * L, struct anchorclass *anchor);
148 void handle_splinefont(lua_State * L, struct splinefont *sf);
149 void handle_kernpair(lua_State * L, struct kernpair *kp);
150 void handle_splinecharlist(lua_State * L, struct splinecharlist *scl);
151 void handle_liglist(lua_State * L, struct liglist *ligofme);
152 void handle_anchorpoint(lua_State * L, struct anchorpoint *anchor);
153 void handle_glyphvariants(lua_State * L, struct glyphvariants *vars);
154 void handle_mathkern(lua_State * L, struct mathkern *mk);
155 int handle_altuni(lua_State * L, struct altuni *au);
156 
is_userdata(lua_State * L,int b,char * utype)157 int is_userdata(lua_State *L, int b, char *utype)
158 {
159     if (lua_type(L,b) == LUA_TUSERDATA) {
160         lua_getmetatable(L, b);
161         luaL_getmetatable(L, utype);
162         if (lua_compare(L, -2, -1, LUA_OPEQ)) {
163             lua_pop(L,2);
164             return 1;
165         }
166         lua_pop(L,2);
167     }
168     return 0;
169 }
170 
171 
172 
lua_ff_pushfont(lua_State * L,SplineFont * sf)173 void lua_ff_pushfont(lua_State * L, SplineFont * sf)
174 {
175     SplineFont **a;
176     if (sf == NULL) {
177         lua_pushnil(L);
178     } else {
179         a = lua_newuserdata(L, sizeof(SplineFont *));
180         *a = sf;
181         luaL_getmetatable(L, FONT_METATABLE);
182         lua_setmetatable(L, -2);
183     }
184     return;
185 }
186 
lua_ff_pushsubfont(lua_State * L,SplineFont * sf)187 void lua_ff_pushsubfont(lua_State * L, SplineFont * sf)
188 {
189     SplineFont **a;
190     if (sf == NULL) {
191         lua_pushnil(L);
192     } else {
193         a = lua_newuserdata(L, sizeof(SplineFont *));
194         *a = sf;
195         luaL_getmetatable(L, FONT_SUBFONT_METATABLE);
196         lua_setmetatable(L, -2);
197     }
198     return;
199 }
200 
lua_ff_pushglyph(lua_State * L,struct splinechar * sc)201 void lua_ff_pushglyph(lua_State * L, struct splinechar *sc)
202 {
203     struct splinechar **a;
204     if (sc == NULL) {
205         lua_pushnil(L);
206     } else {
207         a = lua_newuserdata(L, sizeof(struct splinechar *));
208         *a = sc;
209         luaL_getmetatable(L, FONT_GLYPH_METATABLE);
210         lua_setmetatable(L, -2);
211     }
212     return;
213 }
214 
215 
ff_open(lua_State * L)216 static int ff_open(lua_State * L)
217 {
218     SplineFont *sf;
219     const char *fontname;
220     FILE *l;
221     char s[511];
222     size_t len;
223     int args, i;
224     int openflags = 1 + 4;
225     fontname = luaL_checkstring(L, 1);
226     /* test fontname for existance */
227     if ((l = fopen(fontname, "r"))) {
228         recorder_record_input(fontname);
229         fclose(l);
230     } else {
231         lua_pushnil(L);
232         lua_pushfstring(L, "font loading failed for %s (read error)\n",
233                         fontname);
234         return 2;
235     }
236     args = lua_gettop(L);
237     if (args >= 2 && lua_isstring(L, 2)) {
238         if (*(fontname + strlen(fontname)) != ')') {
239             /* possibly fails for embedded parens in the font name */
240             snprintf(s, 511, "%s(%s)", fontname, lua_tolstring(L, 2, &len));
241             if (len == 0) {
242                 snprintf(s, 511, "%s", fontname);
243             }
244         }
245     } else {
246         snprintf(s, 511, "%s", fontname);
247     }
248     if (strlen(s) > 0) {
249         gww_error_count = 0;
250         sf = ReadSplineFont((char *) s, openflags);
251         if (sf == NULL) {
252             lua_pushnil(L);
253             lua_pushfstring(L, "font loading failed for %s\n", s);
254             if (gww_error_count > 0) {
255                 for (i = 0; i < gww_error_count; i++) {
256                     lua_pushstring(L, gww_errors[i]);
257                     lua_concat(L, 2);
258                 }
259                 gwwv_errors_free();
260             }
261         } else {
262             FVAppend(_FontViewCreate(sf));
263             lua_ff_pushfont(L, sf);
264             if (gww_error_count > 0) {
265                 lua_newtable(L);
266                 for (i = 0; i < gww_error_count; i++) {
267                     lua_pushstring(L, gww_errors[i]);
268                     lua_rawseti(L, -2, (i + 1));
269                 }
270                 gwwv_errors_free();
271             } else {
272                 lua_pushnil(L);
273             }
274         }
275     } else {
276         lua_pushnil(L);
277         lua_pushfstring(L, "font loading failed: empty string given\n",
278                         fontname);
279     }
280     return 2;
281 }
282 
283 
ff_close(lua_State * L)284 static int ff_close(lua_State * L)
285 {
286     SplineFont **sf;
287     /*fputs("ff_close called",stderr); */
288     sf = check_isfont(L, 1);
289     if (*sf != NULL) {
290         if ((*sf)->fv) {        // condition might be improved
291             FontViewClose((*sf)->fv);
292         } else {
293             EncMapFree((*sf)->map);
294             SplineFontFree(*sf);
295         }
296         *sf = NULL;
297     }
298     return 0;
299 }
300 
notdef_loc(SplineFont * sf)301 static int notdef_loc(SplineFont * sf)
302 {
303     int k;
304     int l = -1;
305     for (k = 0; k < sf->glyphcnt; k++) {
306         if (sf->glyphs[k]) {
307             if (strcmp(sf->glyphs[k]->name, ".notdef") == 0) {
308                 l = k;
309             }
310         }
311     }
312     if (l == -1)
313         l = sf->glyphcnt;
314     return l;
315 }
316 
ff_apply_featurefile(lua_State * L)317 static int ff_apply_featurefile(lua_State * L)
318 {
319     SplineFont **sf;
320     char *fname;
321     sf = check_isfont(L, 1);
322     fname = (char *) luaL_checkstring(L, 2);
323     SFApplyFeatureFilename(*sf, fname);
324     if (gww_error_count > 0) {
325 	int i;
326 	lua_newtable(L);
327 	for (i = 0; i < gww_error_count; i++) {
328 	    lua_pushstring(L, gww_errors[i]);
329 	    lua_rawseti(L, -2, (i + 1));
330 	}
331 	gwwv_errors_free();
332     } else {
333 	lua_pushnil(L);
334     }
335     return 1;
336 }
337 
ff_apply_afmfile(lua_State * L)338 static int ff_apply_afmfile(lua_State * L)
339 {
340     SplineFont **sf;
341     char *fname;
342     sf = check_isfont(L, 1);
343     fname = (char *) luaL_checkstring(L, 2);
344     CheckAfmOfPostscript(*sf, fname, (*sf)->map);
345     if (gww_error_count > 0) {
346 	int i;
347 	lua_newtable(L);
348 	for (i = 0; i < gww_error_count; i++) {
349 	    lua_pushstring(L, gww_errors[i]);
350 	    lua_rawseti(L, -2, (i + 1));
351 	}
352 	gwwv_errors_free();
353     } else {
354 	lua_pushnil(L);
355     }
356     return 1;
357 }
358 
359 
360 
dump_intfield(lua_State * L,char * name,long int field)361 static void dump_intfield(lua_State * L, char *name, long int field)
362 {
363     lua_checkstack(L, 2);
364     lua_pushstring(L, name);
365     lua_pushnumber(L, field);
366     lua_rawset(L, -3);
367 }
368 
dump_uintfield(lua_State * L,char * name,unsigned int field)369 static void dump_uintfield(lua_State * L, char *name, unsigned int field)
370 {
371     lua_checkstack(L, 2);
372     lua_pushstring(L, name);
373     lua_pushnumber(L, field);
374     lua_rawset(L, -3);
375 }
376 
dump_realfield(lua_State * L,char * name,real field)377 static void dump_realfield(lua_State * L, char *name, real field)
378 {
379     lua_checkstack(L, 2);
380     lua_pushstring(L, name);
381     lua_pushnumber(L, field);
382     lua_rawset(L, -3);
383 }
384 
385 
386 #define dump_cond_intfield(a,b,c) if ((c)!=0) { dump_intfield ((a),(b),(c)); }
387 
388 
dump_stringfield(lua_State * L,char * name,char * field)389 static void dump_stringfield(lua_State * L, char *name, char *field)
390 {
391     lua_checkstack(L, 2);
392     lua_pushstring(L, name);
393     lua_pushstring(L, field);
394     lua_rawset(L, -3);
395 }
396 
dump_char_ref(lua_State * L,struct splinechar * spchar)397 static void dump_char_ref(lua_State * L, struct splinechar *spchar)
398 {
399     lua_checkstack(L, 2);
400     lua_pushstring(L, "char");
401     lua_pushstring(L, spchar->name);
402     lua_rawset(L, -3);
403 }
404 
405 
dump_lstringfield(lua_State * L,char * name,char * field,int len)406 static void dump_lstringfield(lua_State * L, char *name, char *field, int len)
407 {
408     lua_checkstack(L, 2);
409     lua_pushstring(L, name);
410     lua_pushlstring(L, field, len);
411     lua_rawset(L, -3);
412 }
413 
dump_enumfield(lua_State * L,char * name,int fid,char ** fields)414 static void dump_enumfield(lua_State * L, char *name, int fid, char **fields)
415 {
416     lua_checkstack(L, 2);
417     lua_pushstring(L, name);
418     lua_pushstring(L, fields[fid]);
419     lua_rawset(L, -3);
420 }
421 
dump_floatfield(lua_State * L,char * name,double field)422 static void dump_floatfield(lua_State * L, char *name, double field)
423 {
424     lua_checkstack(L, 2);
425     lua_pushstring(L, name);
426     lua_pushnumber(L, field);
427     lua_rawset(L, -3);
428 }
429 
430 static char tag_string[5] = { 0 };
431 
make_tag_string(unsigned int field)432 static char *make_tag_string(unsigned int field)
433 {
434     tag_string[0] = (field & 0xFF000000) >> 24;
435     tag_string[1] = (field & 0x00FF0000) >> 16;
436     tag_string[2] = (field & 0x0000FF00) >> 8;
437     tag_string[3] = (field & 0x000000FF);
438     return (char *) tag_string;
439 }
440 
441 static char featbuf[32] = { 0 };
442 
443 
444 
dump_tag(lua_State * L,char * name,unsigned int field)445 static void dump_tag(lua_State * L, char *name, unsigned int field)
446 {
447     lua_checkstack(L, 2);
448     lua_pushstring(L, name);
449     lua_pushlstring(L, make_tag_string(field), 4);
450     lua_rawset(L, -3);
451 }
452 
dump_subtable_name(lua_State * L,char * name,struct lookup_subtable * s)453 void dump_subtable_name(lua_State * L, char *name, struct lookup_subtable *s)
454 {
455     /* this is likely a backref */
456     if (s == NULL)
457         return;
458     lua_checkstack(L, 2);
459     if (s->next == NULL) {
460         dump_stringfield(L, name, s->subtable_name);
461     } else {
462         /* can this really happen ? */
463         int i = 0;
464         lua_newtable(L);
465         while (s != NULL) {
466             lua_pushstring(L, s->subtable_name);
467             lua_rawseti(L, -2, ++i);
468             s = s->next;
469         }
470         lua_setfield(L, -2, name);
471     }
472 }
473 
474 
475 
476 #define NESTED_TABLE(a,b,c) {                                           \
477     int k = 1;                                                          \
478     next = b;								\
479     while (next != NULL) {                                              \
480 	lua_checkstack(L,2);						\
481 	lua_pushnumber(L,k); k++;					\
482 	lua_createtable(L,0,c);						\
483 	a(L, next);							\
484 	lua_rawset(L,-3);						\
485 	next = next->next;						\
486     } }
487 
488 #define NESTED_TABLE_SF(a,b,c,d) {                                      \
489     int k = 1;                                                          \
490     next = b;								\
491     while (next != NULL) {                                              \
492 	lua_checkstack(L,2);						\
493 	lua_pushnumber(L,k); k++;					\
494 	lua_createtable(L,0,d);						\
495 	if (a(L, next, c))						\
496 	    lua_rawset(L,-3);						\
497 	else {								\
498 	    lua_pop(L,2);						\
499 	}								\
500 	next = next->next;						\
501     } }
502 
503 
do_handle_scriptlanglist(lua_State * L,struct scriptlanglist * sl)504 void do_handle_scriptlanglist(lua_State * L, struct scriptlanglist *sl)
505 {
506     int k;
507     dump_tag(L, "script", sl->script);
508 
509     lua_checkstack(L, 3);
510     lua_newtable(L);
511     for (k = 0; k < MAX_LANG; k++) {
512         if (sl->langs[k] != 0) {
513             lua_pushnumber(L, (k + 1));
514             lua_pushstring(L, make_tag_string(sl->langs[k]));
515             lua_rawset(L, -3);
516         }
517     }
518 
519     if (sl->lang_cnt >= MAX_LANG) {
520         for (k = MAX_LANG; k < sl->lang_cnt; k++) {
521             lua_pushnumber(L, (k + 1));
522             lua_pushstring(L, make_tag_string(sl->morelangs[k - MAX_LANG]));
523             lua_rawset(L, -3);
524         }
525     }
526     lua_setfield(L, -2, "langs");
527 }
528 
handle_scriptlanglist(lua_State * L,struct scriptlanglist * sll)529 void handle_scriptlanglist(lua_State * L, struct scriptlanglist *sll)
530 {
531     struct scriptlanglist *next;
532     NESTED_TABLE(do_handle_scriptlanglist, sll, 4);
533 }
534 
535 void
do_handle_featurescriptlanglist(lua_State * L,struct featurescriptlanglist * features)536 do_handle_featurescriptlanglist(lua_State * L,
537                                 struct featurescriptlanglist *features)
538 {
539     dump_tag(L, "tag", features->featuretag);
540     lua_newtable(L);
541     handle_scriptlanglist(L, features->scripts);
542     lua_setfield(L, -2, "scripts");
543 }
544 
545 void
handle_featurescriptlanglist(lua_State * L,struct featurescriptlanglist * features)546 handle_featurescriptlanglist(lua_State * L,
547                              struct featurescriptlanglist *features)
548 {
549     struct featurescriptlanglist *next;
550     NESTED_TABLE(do_handle_featurescriptlanglist, features, 3);
551 }
552 
do_handle_lookup_subtable(lua_State * L,struct lookup_subtable * subtable)553 void do_handle_lookup_subtable(lua_State * L, struct lookup_subtable *subtable)
554 {
555 
556     dump_stringfield(L, "name", subtable->subtable_name);
557     dump_stringfield(L, "suffix", subtable->suffix);
558 
559     /* struct otlookup *lookup; *//* this is the parent */
560 
561     /* dump_intfield   (L,"unused",               subtable->unused); */
562     /* The next one is true if there is no fpst, false otherwise */
563     /*
564        dump_intfield      (L,"per_glyph_pst_or_kern",subtable->per_glyph_pst_or_kern);
565      */
566     dump_cond_intfield(L, "anchor_classes", subtable->anchor_classes);
567     dump_cond_intfield(L, "vertical_kerning", subtable->vertical_kerning);
568 
569     if (subtable->kc != NULL) {
570         lua_newtable(L);
571         handle_kernclass(L, subtable->kc, subtable->subtable_name);
572         lua_setfield(L, -2, "kernclass");
573     }
574 #if 0
575     if (subtable->fpst != NULL) {
576         /* lua_newtable(L); */
577         handle_generic_fpst(L, subtable->fpst);
578         /* lua_setfield(L,-2, "fpst"); */
579     }
580 #endif
581 
582     /* int subtable_offset; *//* used by OTF file generation */
583     /* int32 *extra_subtables; *//* used by OTF file generation */
584 }
585 
handle_lookup_subtable(lua_State * L,struct lookup_subtable * subtable)586 void handle_lookup_subtable(lua_State * L, struct lookup_subtable *subtable)
587 {
588     struct lookup_subtable *next;
589     NESTED_TABLE(do_handle_lookup_subtable, subtable, 2);
590 }
591 
do_handle_lookup(lua_State * L,struct otlookup * lookup,SplineFont * sf)592 int do_handle_lookup(lua_State * L, struct otlookup *lookup, SplineFont * sf)
593 {
594     int mc;
595 
596     dump_enumfield(L, "type", lookup->lookup_type, otf_lookup_type_enum);
597 
598     lua_newtable(L);
599     if (lookup->lookup_flags & pst_r2l) {
600         lua_pushstring(L, "r2l");
601         lua_pushboolean(L, 1);
602         lua_rawset(L, -3);
603     }
604     if (lookup->lookup_flags & pst_ignorebaseglyphs) {
605         lua_pushstring(L, "ignorebaseglyphs");
606         lua_pushboolean(L, 1);
607         lua_rawset(L, -3);
608     }
609     if (lookup->lookup_flags & pst_ignoreligatures) {
610         lua_pushstring(L, "ignoreligatures");
611         lua_pushboolean(L, 1);
612         lua_rawset(L, -3);
613     }
614     if (lookup->lookup_flags & pst_ignorecombiningmarks) {
615         lua_pushstring(L, "ignorecombiningmarks");
616         lua_pushboolean(L, 1);
617         lua_rawset(L, -3);
618     }
619     mc = (lookup->lookup_flags >> 8);
620     if (mc > 0 && mc < sf->mark_class_cnt && sf->mark_class_names[mc] != NULL) {
621         lua_pushstring(L, "mark_class");
622         lua_pushstring(L, sf->mark_class_names[mc]);
623         lua_rawset(L, -3);
624     }
625     lua_setfield(L, -2, "flags");
626 
627 
628 
629     dump_stringfield(L, "name", lookup->lookup_name);
630 
631     if (lookup->features != NULL) {
632         lua_newtable(L);
633         handle_featurescriptlanglist(L, lookup->features);
634         lua_setfield(L, -2, "features");
635     }
636 
637     if (lookup->subtables != NULL) {
638         lua_newtable(L);
639         handle_lookup_subtable(L, lookup->subtables);
640         lua_setfield(L, -2, "subtables");
641     }
642 
643     /* dump_intfield   (L,"unused",           lookup->unused);  */
644     /* dump_intfield   (L,"empty",            lookup->empty); */
645     /* dump_intfield   (L,"store_in_afm",     lookup->store_in_afm); */
646     /* dump_intfield   (L,"needs_extension",  lookup->needs_extension); */
647     /* dump_intfield   (L,"temporary_kern",   lookup->temporary_kern); */
648     /* dump_intfield   (L,"def_lang_checked", lookup->def_lang_checked); */
649     /* dump_intfield   (L,"def_lang_found",   lookup->def_lang_found); */
650     /* dump_intfield   (L,"ticked",           lookup->ticked); */
651     /* dump_intfield   (L,"subcnt",           lookup->subcnt); */
652     /* dump_intfield   (L,"lookup_index",     lookup->lookup_index); *//* identical to array index */
653     /* dump_intfield   (L,"lookup_offset",    lookup->lookup_offset); */
654     /* dump_intfield   (L,"lookup_length",    lookup->lookup_length); */
655     /* dump_stringfield(L,"tempname",         lookup->tempname); */
656     return 1;
657 }
658 
handle_lookup(lua_State * L,struct otlookup * lookup,SplineFont * sf)659 void handle_lookup(lua_State * L, struct otlookup *lookup, SplineFont * sf)
660 {
661     struct otlookup *next;
662     NESTED_TABLE_SF(do_handle_lookup, lookup, sf, 18);  /* 18 is a guess */
663 }
664 
do_handle_kernpair(lua_State * L,struct kernpair * kp)665 void do_handle_kernpair(lua_State * L, struct kernpair *kp)
666 {
667 
668     if (kp->sc != NULL)
669         dump_char_ref(L, kp->sc);
670     dump_intfield(L, "off", kp->off);
671     /*  uint16 kcid;   *//* temporary value */
672     dump_subtable_name(L, "lookup", kp->subtable);
673 }
674 
handle_kernpair(lua_State * L,struct kernpair * kp)675 void handle_kernpair(lua_State * L, struct kernpair *kp)
676 {
677     struct kernpair *next;
678     NESTED_TABLE(do_handle_kernpair, kp, 4);
679 }
680 
handle_splinecharlist(lua_State * L,struct splinecharlist * scl)681 void handle_splinecharlist(lua_State * L, struct splinecharlist *scl)
682 {
683 
684     struct splinecharlist *next = scl;
685     int k = 1;
686     lua_checkstack(L, 10);
687     while (next != NULL) {
688         if (next->sc != NULL) {
689             lua_pushnumber(L, k);
690             k++;
691             lua_pushstring(L, next->sc->name);
692             lua_rawset(L, -3);
693         }
694         next = next->next;
695     }
696 }
697 
698 
699 
700 /* vs is the "variation selector" a unicode codepoint which modifieds */
701 /*  the code point before it. If vs is -1 then unienc is just an */
702 /*  alternate encoding (greek Alpha and latin A), but if vs is one */
703 /*  of unicode's variation selectors then this glyph is somehow a */
704 /*  variant shape. The specifics depend on the selector and script */
705 /*  fid is currently unused, but may, someday, be used to do ttcs */
706 /* NOTE: GlyphInfo displays vs==-1 as vs==0, and fixes things up */
handle_altuni(lua_State * L,struct altuni * au)707 int handle_altuni(lua_State * L, struct altuni *au)
708 {
709     struct altuni *next = au;
710     int i = 0;
711     int k = 1;
712     lua_checkstack(L, 3);
713     while (next != NULL) {
714 	if (next->unienc<0x10FFF) {
715 	    lua_newtable(L);
716 	    dump_intfield(L, "unicode", next->unienc);
717 	    i++;
718 	    if (next->vs != -1)
719 		dump_intfield(L, "variant", next->vs);
720 	    /* dump_intfield(L, "fid", next->fid); */
721 	    lua_rawseti(L, -2, k++);
722 	}
723         next = next->next;
724     }
725     return i;
726 }
727 
728 
729 
730 #define interesting_vr(a) (((a)->xoff!=0) || ((a)->yoff!=0) || ((a)->h_adv_off!=0) || ((a)->v_adv_off!=0))
731 
handle_vr(lua_State * L,struct vr * pos)732 void handle_vr(lua_State * L, struct vr *pos)
733 {
734 
735     dump_cond_intfield(L, "x", pos->xoff);
736     dump_cond_intfield(L, "y", pos->yoff);
737     dump_cond_intfield(L, "h", pos->h_adv_off);
738     dump_cond_intfield(L, "v", pos->v_adv_off);
739 
740 }
741 
do_handle_generic_pst(lua_State * L,struct generic_pst * pst)742 void do_handle_generic_pst(lua_State * L, struct generic_pst *pst)
743 {
744     int k;
745     if (pst->type > LAST_POSSUB_TYPE_ENUM) {
746         dump_tag(L, "type", pst->type);
747     } else {
748         dump_enumfield(L, "type", pst->type, possub_type_enum);
749     }
750     /*  unsigned int ticked: 1; */
751     /*  unsigned int temporary: 1; *//* Used in afm ligature closure */
752     /*  struct lookup_subtable *subtable; *//* handled by caller */
753 
754     lua_checkstack(L, 4);
755     lua_pushstring(L, "specification");
756     lua_createtable(L, 0, 4);
757     if (pst->type == pst_position) {
758         handle_vr(L, &pst->u.pos);
759     } else if (pst->type == pst_pair) {
760         dump_stringfield(L, "paired", pst->u.pair.paired);
761         if (pst->u.pair.vr != NULL) {
762             lua_pushstring(L, "offsets");
763             lua_createtable(L, 2, 0);
764             if (interesting_vr(pst->u.pair.vr)) {
765                 lua_createtable(L, 0, 4);
766                 handle_vr(L, pst->u.pair.vr);
767                 lua_rawseti(L, -2, 1);
768             }
769             if (interesting_vr(pst->u.pair.vr + 1)) {
770                 lua_createtable(L, 0, 4);
771                 handle_vr(L, pst->u.pair.vr + 1);
772                 lua_rawseti(L, -2, 2);
773             }
774             lua_rawset(L, -3);
775         }
776     } else if (pst->type == pst_substitution) {
777         dump_stringfield(L, "variant", pst->u.subs.variant);
778     } else if (pst->type == pst_alternate) {
779         dump_stringfield(L, "components", pst->u.mult.components);
780     } else if (pst->type == pst_multiple) {
781         dump_stringfield(L, "components", pst->u.alt.components);
782     } else if (pst->type == pst_ligature) {
783         dump_stringfield(L, "components", pst->u.lig.components);
784         if (pst->u.lig.lig != NULL) {
785             dump_char_ref(L, pst->u.lig.lig);
786         }
787     } else if (pst->type == pst_lcaret) {
788         for (k = 0; k < pst->u.lcaret.cnt; k++) {
789             lua_pushnumber(L, (k + 1));
790             lua_pushnumber(L, pst->u.lcaret.carets[k]);
791             lua_rawset(L, -3);
792         }
793     }
794     lua_rawset(L, -3);
795 }
796 
797 
handle_generic_pst(lua_State * L,struct generic_pst * pst)798 void handle_generic_pst(lua_State * L, struct generic_pst *pst)
799 {
800     struct generic_pst *next;
801     int k;
802     int l = 1;
803     next = pst;
804     /* most likely everything arrives in proper order. But to prevent
805      * surprises, better do this is the proper way
806      */
807     while (next != NULL) {
808         if (next->subtable != NULL && next->subtable->subtable_name != NULL) {
809             lua_checkstack(L, 3);       /* just in case */
810             lua_getfield(L, -1, next->subtable->subtable_name);
811             if (!lua_istable(L, -1)) {
812                 lua_pop(L, 1);
813                 lua_newtable(L);
814                 lua_setfield(L, -2, next->subtable->subtable_name);
815                 lua_getfield(L, -1, next->subtable->subtable_name);
816             }
817             k = lua_rawlen(L, -1) + 1;
818             lua_pushnumber(L, k);
819             lua_createtable(L, 0, 4);
820             do_handle_generic_pst(L, next);
821             lua_rawset(L, -3);
822             next = next->next;
823             lua_pop(L, 1);      /* pop the subtable */
824         } else {
825             /* Found a pst without subtable, or without subtable name */
826             lua_pushnumber(L, l);
827             l++;
828             lua_createtable(L, 0, 4);
829             do_handle_generic_pst(L, next);
830             lua_rawset(L, -3);
831             next = next->next;
832         }
833     }
834 }
835 
do_handle_liglist(lua_State * L,struct liglist * ligofme)836 void do_handle_liglist(lua_State * L, struct liglist *ligofme)
837 {
838     lua_checkstack(L, 2);
839     if (ligofme->lig != NULL) {
840         lua_createtable(L, 0, 6);
841         handle_generic_pst(L, ligofme->lig);
842         lua_setfield(L, -2, "lig");
843     }
844     dump_char_ref(L, ligofme->first);
845     if (ligofme->components != NULL) {
846         lua_newtable(L);
847         handle_splinecharlist(L, ligofme->components);
848         lua_setfield(L, -2, "components");
849     }
850     dump_intfield(L, "ccnt", ligofme->ccnt);
851 }
852 
853 
handle_liglist(lua_State * L,struct liglist * ligofme)854 void handle_liglist(lua_State * L, struct liglist *ligofme)
855 {
856     struct liglist *next;
857     NESTED_TABLE(do_handle_liglist, ligofme, 3);
858 }
859 
do_handle_anchorpoint(lua_State * L,struct anchorpoint * anchor)860 void do_handle_anchorpoint(lua_State * L, struct anchorpoint *anchor)
861 {
862 
863     if (anchor->anchor == NULL) {
864         return;
865     }
866     if (anchor->type >= 0 && anchor->type <= MAX_ANCHOR_TYPE) {
867         lua_pushstring(L, anchor_type_enum[anchor->type]);
868     } else {
869         lua_pushstring(L, "Anchorpoint has an unknown type!");
870         lua_error(L);
871     }
872     /* unsigned int selected: 1; */
873     /* unsigned int ticked: 1; */
874 
875     lua_rawget(L, -2);
876     if (!lua_istable(L, -1)) {
877         /* create the table first */
878         lua_pop(L, 1);
879         lua_pushstring(L, anchor_type_enum[anchor->type]);
880         lua_pushvalue(L, -1);
881         lua_newtable(L);
882         lua_rawset(L, -4);
883         lua_rawget(L, -2);
884     }
885     /* now the 'type' table is top of stack */
886     if (anchor->type == at_baselig) {
887         lua_pushstring(L, anchor->anchor->name);
888         lua_rawget(L, -2);
889         if (!lua_istable(L, -1)) {
890             /* create the table first */
891             lua_pop(L, 1);
892             lua_pushstring(L, anchor->anchor->name);
893             lua_pushvalue(L, -1);
894             lua_newtable(L);
895             lua_rawset(L, -4);
896             lua_rawget(L, -2);
897         }
898         lua_newtable(L);
899         dump_intfield(L, "x", anchor->me.x);
900         dump_intfield(L, "y", anchor->me.y);
901         if (anchor->has_ttf_pt)
902             dump_intfield(L, "ttf_pt_index", anchor->ttf_pt_index);
903         dump_intfield(L, "lig_index", anchor->lig_index);
904         lua_rawseti(L, -2, (anchor->lig_index + 1));
905         lua_pop(L, 1);
906     } else {
907         lua_pushstring(L, anchor->anchor->name);
908         lua_newtable(L);
909         dump_intfield(L, "x", anchor->me.x);
910         dump_intfield(L, "y", anchor->me.y);
911         if (anchor->has_ttf_pt)
912             dump_intfield(L, "ttf_pt_index", anchor->ttf_pt_index);
913         dump_intfield(L, "lig_index", anchor->lig_index);
914         lua_rawset(L, -3);
915     }
916     lua_pop(L, 1);
917 }
918 
919 
handle_anchorpoint(lua_State * L,struct anchorpoint * anchor)920 void handle_anchorpoint(lua_State * L, struct anchorpoint *anchor)
921 {
922     struct anchorpoint *next;
923     next = anchor;
924     while (next != NULL) {
925         do_handle_anchorpoint(L, next);
926         next = next->next;
927     }
928 }
929 
handle_glyphvariants(lua_State * L,struct glyphvariants * vars)930 void handle_glyphvariants(lua_State * L, struct glyphvariants *vars)
931 {
932     int i;
933     dump_stringfield(L, "variants", vars->variants);
934     dump_intfield(L, "italic_correction", vars->italic_correction);
935     lua_newtable(L);
936     for (i = 0; i < vars->part_cnt; i++) {
937         lua_newtable(L);
938         dump_stringfield(L, "component", vars->parts[i].component);
939         dump_intfield(L, "extender", vars->parts[i].is_extender);
940         dump_intfield(L, "start", vars->parts[i].startConnectorLength);
941         dump_intfield(L, "end", vars->parts[i].endConnectorLength);
942         dump_intfield(L, "advance", vars->parts[i].fullAdvance);
943         lua_rawseti(L, -2, (i + 1));
944     }
945     lua_setfield(L, -2, "parts");
946 }
947 
handle_mathkernvertex(lua_State * L,struct mathkernvertex * mkv)948 void handle_mathkernvertex(lua_State * L, struct mathkernvertex *mkv)
949 {
950     int i;
951     for (i = 0; i < mkv->cnt; i++) {
952         lua_newtable(L);
953         dump_intfield(L, "height", mkv->mkd[i].height);
954         dump_intfield(L, "kern", mkv->mkd[i].kern);
955         lua_rawseti(L, -2, (i + 1));
956     }
957 }
958 
handle_mathkern(lua_State * L,struct mathkern * mk)959 void handle_mathkern(lua_State * L, struct mathkern *mk)
960 {
961     lua_newtable(L);
962     handle_mathkernvertex(L, &(mk->top_right));
963     lua_setfield(L, -2, "top_right");
964     lua_newtable(L);
965     handle_mathkernvertex(L, &(mk->top_left));
966     lua_setfield(L, -2, "top_left");
967     lua_newtable(L);
968     handle_mathkernvertex(L, &(mk->bottom_right));
969     lua_setfield(L, -2, "bottom_right");
970     lua_newtable(L);
971     handle_mathkernvertex(L, &(mk->bottom_left));
972     lua_setfield(L, -2, "bottom_left");
973 }
974 
975 
976 
handle_splinechar(lua_State * L,struct splinechar * glyph,int hasvmetrics)977 void handle_splinechar(lua_State * L, struct splinechar *glyph, int hasvmetrics)
978 {
979     DBounds bb;
980     if (glyph->xmax == 0 && glyph->ymax == 0 && glyph->xmin == 0
981         && glyph->ymin == 0) {
982         SplineCharFindBounds(glyph, &bb);
983         glyph->xmin = bb.minx;
984         glyph->ymin = bb.miny;
985         glyph->xmax = bb.maxx;
986         glyph->ymax = bb.maxy;
987     }
988     dump_stringfield(L, "name", glyph->name);
989     dump_intfield(L, "unicode", glyph->unicodeenc);
990     lua_createtable(L, 4, 0);
991     lua_pushnumber(L, 1);
992     lua_pushnumber(L, glyph->xmin);
993     lua_rawset(L, -3);
994     lua_pushnumber(L, 2);
995     lua_pushnumber(L, glyph->ymin);
996     lua_rawset(L, -3);
997     lua_pushnumber(L, 3);
998     lua_pushnumber(L, glyph->xmax);
999     lua_rawset(L, -3);
1000     lua_pushnumber(L, 4);
1001     lua_pushnumber(L, glyph->ymax);
1002     lua_rawset(L, -3);
1003     lua_setfield(L, -2, "boundingbox");
1004     /*dump_intfield(L,"orig_pos",       glyph->orig_pos); */
1005     if (hasvmetrics) {
1006         dump_intfield(L, "vwidth", glyph->vwidth);
1007         if (glyph->tsb != 0)
1008            dump_intfield(L, "tsidebearing", glyph->tsb);
1009     }
1010     dump_intfield(L, "width", glyph->width);
1011 
1012     if (glyph->lsidebearing != glyph->xmin) {
1013         dump_cond_intfield(L, "lsidebearing", glyph->lsidebearing);
1014     }
1015     /* dump_intfield(L,"ttf_glyph",   glyph->ttf_glyph);  */
1016 
1017     /* Layer layers[2];   *//* TH Not used */
1018     /*  int layer_cnt;    *//* TH Not used */
1019     /*  StemInfo *hstem;  *//* TH Not used */
1020     /*  StemInfo *vstem;  *//* TH Not used */
1021     /*  DStemInfo *dstem; *//* TH Not used */
1022 
1023     /* MinimumDistance *md; *//* TH Not used */
1024     /* struct charviewbase *views; *//* TH Not used */
1025     /* struct charinfo *charinfo;  *//* TH ? (charinfo.c) */
1026     /* struct splinefont *parent;  *//* TH Not used */
1027 
1028     if (glyph->glyph_class > 0) {
1029         dump_enumfield(L, "class", glyph->glyph_class, glyph_class_enum);
1030     }
1031     /* TH: internal fontforge stuff
1032        dump_intfield(L,"changed",                  glyph->changed);
1033        dump_intfield(L,"changedsincelasthinted",   glyph->changedsincelasthinted);
1034        dump_intfield(L,"manualhints",              glyph->manualhints);
1035        dump_intfield(L,"ticked",                   glyph->ticked);
1036        dump_intfield(L,"changed_since_autosave",   glyph->changed_since_autosave);
1037        dump_intfield(L,"widthset",                 glyph->widthset);
1038        dump_intfield(L,"vconflicts",               glyph->vconflicts);
1039        dump_intfield(L,"hconflicts",               glyph->hconflicts);
1040        dump_intfield(L,"searcherdummy",            glyph->searcherdummy);
1041        dump_intfield(L,"changed_since_search",     glyph->changed_since_search);
1042        dump_intfield(L,"wasopen",                  glyph->wasopen);
1043        dump_intfield(L,"namechanged",              glyph->namechanged);
1044        dump_intfield(L,"blended",                  glyph->blended);
1045        dump_intfield(L,"ticked2",                  glyph->ticked2);
1046        dump_intfield(L,"unused_so_far",            glyph->unused_so_far);
1047        dump_intfield(L,"numberpointsbackards",     glyph->numberpointsbackards);
1048        dump_intfield(L,"instructions_out_of_date", glyph->instructions_out_of_date);
1049        dump_intfield(L,"complained_about_ptnums",  glyph->complained_about_ptnums);
1050        unsigned int vs_open: 1;
1051        unsigned int unlink_rm_ovrlp_save_undo: 1;
1052        unsigned int inspiro: 1;
1053        unsigned int lig_caret_cnt_fixed: 1;
1054 
1055 
1056        uint8 *ttf_instrs;
1057        int16 ttf_instrs_len;
1058        int16 countermask_cnt;
1059        HintMask *countermasks;
1060      */
1061 
1062     if (glyph->kerns != NULL) {
1063         lua_newtable(L);
1064         handle_kernpair(L, glyph->kerns);
1065         lua_setfield(L, -2, "kerns");
1066     }
1067     if (glyph->vkerns != NULL) {
1068         lua_newtable(L);
1069         handle_kernpair(L, glyph->vkerns);
1070         lua_setfield(L, -2, "vkerns");
1071     }
1072 
1073     if (glyph->dependents != NULL) {
1074         lua_newtable(L);
1075         handle_splinecharlist(L, glyph->dependents);
1076         lua_setfield(L, -2, "dependents");
1077 
1078     }
1079     if (glyph->possub != NULL) {
1080         lua_newtable(L);
1081         handle_generic_pst(L, glyph->possub);
1082         lua_setfield(L, -2, "lookups");
1083     }
1084 
1085     if (glyph->ligofme != NULL) {
1086         lua_newtable(L);
1087         handle_liglist(L, glyph->ligofme);
1088         lua_setfield(L, -2, "ligatures");
1089     }
1090 
1091     if (glyph->comment != NULL)
1092         dump_stringfield(L, "comment", glyph->comment);
1093 
1094     /* Color color;  *//* dont care */
1095 
1096     if (glyph->anchor != NULL) {
1097         lua_newtable(L);
1098         handle_anchorpoint(L, glyph->anchor);
1099         lua_setfield(L, -2, "anchors");
1100     }
1101 
1102     if (glyph->altuni != NULL) {
1103 	int i;
1104         lua_newtable(L);
1105         i = handle_altuni(L, glyph->altuni);
1106 	if (i>0) {
1107 	    lua_setfield(L, -2, "altuni");
1108 	} else {
1109 	    lua_pop(L,1);
1110 	}
1111     }
1112 
1113     if (glyph->tex_height != TEX_UNDEF)
1114         dump_intfield(L, "tex_height", glyph->tex_height);
1115     if (glyph->tex_depth != TEX_UNDEF)
1116         dump_intfield(L, "tex_depth", glyph->tex_depth);
1117 
1118     dump_cond_intfield(L, "is_extended_shape", glyph->is_extended_shape);
1119     if (glyph->italic_correction != TEX_UNDEF)
1120         dump_intfield(L, "italic_correction", glyph->italic_correction);
1121     if (glyph->top_accent_horiz != TEX_UNDEF)
1122         dump_intfield(L, "top_accent", glyph->top_accent_horiz);
1123 
1124     if (glyph->vert_variants != NULL) {
1125         lua_newtable(L);
1126         handle_glyphvariants(L, glyph->vert_variants);
1127         lua_setfield(L, -2, "vert_variants");
1128     }
1129     if (glyph->horiz_variants != NULL) {
1130         lua_newtable(L);
1131         handle_glyphvariants(L, glyph->horiz_variants);
1132         lua_setfield(L, -2, "horiz_variants");
1133     }
1134     if (glyph->mathkern != NULL) {
1135         lua_newtable(L);
1136         handle_mathkern(L, glyph->mathkern);
1137         lua_setfield(L, -2, "mathkern");
1138     }
1139 }
1140 
1141 char *panose_values_0[] =
1142     { "Any", "No Fit", "Text and Display", "Script", "Decorative",
1143     "Pictorial"
1144 };
1145 
1146 char *panose_values_1[] =
1147     { "Any", "No Fit", "Cove", "Obtuse Cove", "Square Cove",
1148     "Obtuse Square Cove",
1149     "Square", "Thin", "Bone", "Exaggerated", "Triangle", "Normal Sans",
1150     "Obtuse Sans", "Perp Sans", "Flared", "Rounded"
1151 };
1152 
1153 char *panose_values_2[] =
1154     { "Any", "No Fit", "Very Light", "Light", "Thin", "Book",
1155     "Medium", "Demi", "Bold", "Heavy", "Black", "Nord"
1156 };
1157 
1158 char *panose_values_3[] =
1159     { "Any", "No Fit", "Old Style", "Modern", "Even Width",
1160     "Expanded", "Condensed", "Very Expanded", "Very Condensed", "Monospaced"
1161 };
1162 
1163 char *panose_values_4[] =
1164     { "Any", "No Fit", "None", "Very Low", "Low", "Medium Low",
1165     "Medium", "Medium High", "High", "Very High"
1166 };
1167 
1168 char *panose_values_5[] =
1169     { "Any", "No Fit", "Gradual/Diagonal", "Gradual/Transitional",
1170     "Gradual/Vertical",
1171     "Gradual/Horizontal", "Rapid/Vertical", "Rapid/Horizontal",
1172     "Instant/Vertical"
1173 };
1174 
1175 char *panose_values_6[] =
1176     { "Any", "No Fit", "Straight Arms/Horizontal", "Straight Arms/Wedge",
1177     "Straight Arms/Vertical",
1178     "Straight Arms/Single Serif", "Straight Arms/Double Serif",
1179     "Non-Straight Arms/Horizontal",
1180     "Non-Straight Arms/Wedge", "Non-Straight Arms/Vertical",
1181     "Non-Straight Arms/Single Serif",
1182     "Non-Straight Arms/Double Serif"
1183 };
1184 
1185 char *panose_values_7[] =
1186     { "Any", "No Fit", "Normal/Contact", "Normal/Weighted", "Normal/Boxed",
1187     "Normal/Flattened",
1188     "Normal/Rounded", "Normal/Off Center", "Normal/Square", "Oblique/Contact",
1189     "Oblique/Weighted",
1190     "Oblique/Boxed", "Oblique/Flattened", "Oblique/Rounded",
1191     "Oblique/Off Center", "Oblique/Square"
1192 };
1193 
1194 char *panose_values_8[] =
1195     { "Any", "No Fit", "Standard/Trimmed", "Standard/Pointed",
1196     "Standard/Serifed", "High/Trimmed",
1197     "High/Pointed", "High/Serifed", "Constant/Trimmed", "Constant/Pointed",
1198     "Constant/Serifed",
1199     "Low/Trimmed", "Low/Pointed", "Low/Serifed"
1200 };
1201 
1202 char *panose_values_9[] =
1203     { "Any", "No Fit", "Constant/Small", "Constant/Standard",
1204     "Constant/Large", "Ducking/Small", "Ducking/Standard", "Ducking/Large"
1205 };
1206 
1207 #define panose_values_0_max 5
1208 #define panose_values_1_max 15
1209 #define panose_values_2_max 11
1210 #define panose_values_3_max 9
1211 #define panose_values_4_max 9
1212 #define panose_values_5_max 8
1213 #define panose_values_6_max 11
1214 #define panose_values_7_max 15
1215 #define panose_values_8_max 13
1216 #define panose_values_9_max 7
1217 
1218 #define fix_range(a,b) (b<0 ? 0 : (b>a ? 0 : b))
1219 
handle_pfminfo(lua_State * L,struct pfminfo pfm)1220 void handle_pfminfo(lua_State * L, struct pfminfo pfm)
1221 {
1222 
1223     dump_intfield(L, "pfmset", pfm.pfmset);
1224     dump_intfield(L, "winascent_add", pfm.winascent_add);
1225     dump_intfield(L, "windescent_add", pfm.windescent_add);
1226     dump_intfield(L, "hheadascent_add", pfm.hheadascent_add);
1227     dump_intfield(L, "hheaddescent_add", pfm.hheaddescent_add);
1228     dump_intfield(L, "typoascent_add", pfm.typoascent_add);
1229     dump_intfield(L, "typodescent_add", pfm.typodescent_add);
1230     dump_intfield(L, "subsuper_set", pfm.subsuper_set);
1231     dump_intfield(L, "panose_set", pfm.panose_set);
1232     dump_intfield(L, "hheadset", pfm.hheadset);
1233     dump_intfield(L, "vheadset", pfm.vheadset);
1234     dump_intfield(L, "pfmfamily", pfm.pfmfamily);
1235     dump_intfield(L, "weight", pfm.weight);
1236     dump_intfield(L, "width", pfm.width);
1237     dump_intfield(L, "avgwidth", pfm.avgwidth);
1238     dump_intfield(L, "firstchar", pfm.firstchar);
1239     dump_intfield(L, "lastchar", pfm.lastchar);
1240     lua_createtable(L, 0, 10);
1241     dump_enumfield(L, "familytype",
1242                    fix_range(panose_values_0_max, pfm.panose[0]),
1243                    panose_values_0);
1244     dump_enumfield(L, "serifstyle",
1245                    fix_range(panose_values_1_max, pfm.panose[1]),
1246                    panose_values_1);
1247     dump_enumfield(L, "weight", fix_range(panose_values_2_max, pfm.panose[2]),
1248                    panose_values_2);
1249     dump_enumfield(L, "proportion",
1250                    fix_range(panose_values_3_max, pfm.panose[3]),
1251                    panose_values_3);
1252     dump_enumfield(L, "contrast", fix_range(panose_values_4_max, pfm.panose[4]),
1253                    panose_values_4);
1254     dump_enumfield(L, "strokevariation",
1255                    fix_range(panose_values_5_max, pfm.panose[5]),
1256                    panose_values_5);
1257     dump_enumfield(L, "armstyle", fix_range(panose_values_6_max, pfm.panose[6]),
1258                    panose_values_6);
1259     dump_enumfield(L, "letterform",
1260                    fix_range(panose_values_7_max, pfm.panose[7]),
1261                    panose_values_7);
1262     dump_enumfield(L, "midline", fix_range(panose_values_8_max, pfm.panose[8]),
1263                    panose_values_8);
1264     dump_enumfield(L, "xheight", fix_range(panose_values_9_max, pfm.panose[9]),
1265                    panose_values_9);
1266     lua_setfield(L, -2, "panose");
1267 
1268     dump_intfield(L, "fstype", pfm.fstype);
1269     dump_intfield(L, "linegap", pfm.linegap);
1270     dump_intfield(L, "vlinegap", pfm.vlinegap);
1271     dump_intfield(L, "hhead_ascent", pfm.hhead_ascent);
1272     dump_intfield(L, "hhead_descent", pfm.hhead_descent);
1273     dump_intfield(L, "hhead_descent", pfm.hhead_descent);
1274     dump_intfield(L, "os2_typoascent", pfm.os2_typoascent);
1275     dump_intfield(L, "os2_typodescent", pfm.os2_typodescent);
1276     dump_intfield(L, "os2_typolinegap", pfm.os2_typolinegap);
1277     dump_intfield(L, "os2_winascent", pfm.os2_winascent);
1278     dump_intfield(L, "os2_windescent", pfm.os2_windescent);
1279     dump_intfield(L, "os2_subxsize", pfm.os2_subxsize);
1280     dump_intfield(L, "os2_subysize", pfm.os2_subysize);
1281     dump_intfield(L, "os2_subxoff", pfm.os2_subxoff);
1282     dump_intfield(L, "os2_subyoff", pfm.os2_subyoff);
1283     dump_intfield(L, "os2_supxsize", pfm.os2_supxsize);
1284     dump_intfield(L, "os2_supysize", pfm.os2_supysize);
1285     dump_intfield(L, "os2_supxoff", pfm.os2_supxoff);
1286     dump_intfield(L, "os2_supyoff", pfm.os2_supyoff);
1287     dump_intfield(L, "os2_strikeysize", pfm.os2_strikeysize);
1288     dump_intfield(L, "os2_strikeypos", pfm.os2_strikeypos);
1289     dump_lstringfield(L, "os2_vendor", pfm.os2_vendor, 4);
1290     dump_intfield(L, "os2_family_class", pfm.os2_family_class);
1291     dump_intfield(L, "os2_xheight", pfm.os2_xheight);
1292     dump_intfield(L, "os2_capheight", pfm.os2_capheight);
1293     dump_intfield(L, "os2_defaultchar", pfm.os2_defaultchar);
1294     dump_intfield(L, "os2_breakchar", pfm.os2_breakchar);
1295     if (pfm.hascodepages) {
1296         lua_newtable(L);
1297         lua_pushnumber(L, pfm.codepages[0]);
1298         lua_rawseti(L, -2, 1);
1299         lua_pushnumber(L, pfm.codepages[1]);
1300         lua_rawseti(L, -2, 2);
1301         lua_setfield(L, -2, "codepages");
1302     }
1303     if (pfm.hasunicoderanges) {
1304         lua_newtable(L);
1305         lua_pushnumber(L, pfm.unicoderanges[0]);
1306         lua_rawseti(L, -2, 1);
1307         lua_pushnumber(L, pfm.unicoderanges[1]);
1308         lua_rawseti(L, -2, 2);
1309         lua_pushnumber(L, pfm.unicoderanges[2]);
1310         lua_rawseti(L, -2, 3);
1311         lua_pushnumber(L, pfm.unicoderanges[3]);
1312         lua_rawseti(L, -2, 4);
1313         lua_setfield(L, -2, "unicoderanges");
1314     }
1315 }
1316 
1317 
do_handle_enc(lua_State * L,struct enc * enc)1318 char *do_handle_enc(lua_State * L, struct enc *enc)
1319 {
1320     int i;
1321     char *ret = enc->enc_name;
1322     dump_stringfield(L, "enc_name", enc->enc_name);
1323     dump_intfield(L, "char_cnt", enc->char_cnt);
1324 
1325     lua_checkstack(L, 4);
1326     if (enc->char_cnt && enc->unicode != NULL) {
1327         lua_createtable(L, enc->char_cnt, 1);
1328         for (i = 0; i < enc->char_cnt; i++) {
1329             lua_pushnumber(L, i);
1330             lua_pushnumber(L, enc->unicode[i]);
1331             lua_rawset(L, -3);
1332         }
1333         lua_setfield(L, -2, "unicode");
1334     }
1335 
1336     if (enc->char_cnt && enc->psnames != NULL) {
1337         lua_createtable(L, enc->char_cnt, 1);
1338         for (i = 0; i < enc->char_cnt; i++) {
1339             lua_pushnumber(L, i);
1340             lua_pushstring(L, enc->psnames[i]);
1341             lua_rawset(L, -3);
1342         }
1343         lua_setfield(L, -2, "psnames");
1344     }
1345     dump_intfield(L, "builtin", enc->builtin);
1346     dump_intfield(L, "hidden", enc->hidden);
1347     dump_intfield(L, "only_1byte", enc->only_1byte);
1348     dump_intfield(L, "has_1byte", enc->has_1byte);
1349     dump_intfield(L, "has_2byte", enc->has_2byte);
1350     dump_cond_intfield(L, "is_unicodebmp", enc->is_unicodebmp);
1351     dump_cond_intfield(L, "is_unicodefull", enc->is_unicodefull);
1352     dump_cond_intfield(L, "is_custom", enc->is_custom);
1353     dump_cond_intfield(L, "is_original", enc->is_original);
1354     dump_cond_intfield(L, "is_compact", enc->is_compact);
1355     dump_cond_intfield(L, "is_japanese", enc->is_japanese);
1356     dump_cond_intfield(L, "is_korean", enc->is_korean);
1357     dump_cond_intfield(L, "is_tradchinese", enc->is_tradchinese);
1358     dump_cond_intfield(L, "is_simplechinese", enc->is_simplechinese);
1359 
1360     if (enc->iso_2022_escape_len > 0) {
1361         dump_lstringfield(L, "iso_2022_escape", enc->iso_2022_escape,
1362                           enc->iso_2022_escape_len);
1363     }
1364     dump_intfield(L, "low_page", enc->low_page);
1365     dump_intfield(L, "high_page", enc->high_page);
1366 
1367     dump_stringfield(L, "iconv_name", enc->iconv_name);
1368 
1369     dump_intfield(L, "char_max", enc->char_max);
1370     return ret;
1371 }
1372 
handle_enc(lua_State * L,struct enc * enc)1373 void handle_enc(lua_State * L, struct enc *enc)
1374 {
1375     struct enc *next;
1376     NESTED_TABLE(do_handle_enc, enc, 24);
1377 }
1378 
handle_encmap(lua_State * L,struct encmap * map,int notdef_loc)1379 void handle_encmap(lua_State * L, struct encmap *map, int notdef_loc)
1380 {
1381     int i;
1382     dump_intfield(L, "enccount", map->enccount);
1383     dump_intfield(L, "encmax", map->encmax);
1384     dump_intfield(L, "backmax", map->backmax);
1385     /*dump_intfield(L,"ticked",   map->ticked) ; */
1386     if (map->remap != NULL) {
1387         lua_newtable(L);
1388         dump_intfield(L, "firstenc", map->remap->firstenc);
1389         dump_intfield(L, "lastenc", map->remap->lastenc);
1390         dump_intfield(L, "infont", map->remap->infont);
1391         lua_setfield(L, -2, "remap");
1392     }
1393     lua_checkstack(L, 4);
1394     if (map->encmax > 0 && map->map != NULL) {
1395         lua_createtable(L, map->encmax, 1);
1396         for (i = 0; i < map->encmax; i++) {
1397             if (map->map[i] != -1) {
1398                 int l = map->map[i];
1399                 lua_pushnumber(L, i);
1400                 if (l < notdef_loc)
1401                     lua_pushnumber(L, (l + 1));
1402                 else
1403                     lua_pushnumber(L, l);
1404                 lua_rawset(L, -3);
1405             }
1406         }
1407         lua_setfield(L, -2, "map");
1408     }
1409 
1410     if (map->backmax > 0 && map->backmap != NULL) {
1411         lua_newtable(L);
1412         for (i = 0; i < map->backmax; i++) {
1413             if (map->backmap[i] != -1) {        /* TODO: check this, because valgrind sometimes says
1414                                                    "Conditional jump or move depends on uninitialised value(s)"
1415                                                    needs a test file.
1416                                                  */
1417                 if (i < notdef_loc)
1418                     lua_pushnumber(L, (i + 1));
1419                 else
1420                     lua_pushnumber(L, i);
1421                 lua_pushnumber(L, map->backmap[i]);
1422                 lua_rawset(L, -3);
1423             }
1424         }
1425         lua_setfield(L, -2, "backmap");
1426     }
1427 
1428     if (map->enc != NULL) {
1429 	char *encname;
1430         lua_newtable(L);
1431         encname = do_handle_enc(L, map->enc);
1432         lua_setfield(L, -2, "enc");
1433 	lua_pushstring(L, encname);
1434         lua_setfield(L, -2, "enc_name");
1435     }
1436 }
1437 
handle_psdict(lua_State * L,struct psdict * private)1438 static void handle_psdict(lua_State * L, struct psdict *private)
1439 {
1440     int k;
1441     if (private->keys != NULL && private->values != NULL) {
1442         for (k = 0; k < private->next; k++) {
1443             lua_pushstring(L, private->keys[k]);
1444             lua_pushstring(L, private->values[k]);
1445             lua_rawset(L, -3);
1446         }
1447     }
1448 }
1449 
do_handle_ttflangname(lua_State * L,struct ttflangname * names)1450 void do_handle_ttflangname(lua_State * L, struct ttflangname *names)
1451 {
1452     int k;
1453     dump_stringfield(L, "lang", (char *) MSLangString(names->lang));
1454     lua_checkstack(L, 4);
1455     lua_createtable(L, 0, ttf_namemax);
1456     for (k = 0; k < ttf_namemax; k++) {
1457         lua_pushstring(L, ttfnames_enum[k]);
1458         lua_pushstring(L, names->names[k]);
1459         lua_rawset(L, -3);
1460     }
1461     lua_setfield(L, -2, "names");
1462 }
1463 
1464 
handle_ttflangname(lua_State * L,struct ttflangname * names)1465 void handle_ttflangname(lua_State * L, struct ttflangname *names)
1466 {
1467     struct ttflangname *next;
1468     NESTED_TABLE(do_handle_ttflangname, names, 2);
1469 }
1470 
1471 
do_handle_anchorclass(lua_State * L,struct anchorclass * anchor)1472 void do_handle_anchorclass(lua_State * L, struct anchorclass *anchor)
1473 {
1474 
1475     dump_stringfield(L, "name", anchor->name);
1476     dump_subtable_name(L, "lookup", anchor->subtable);
1477     dump_enumfield(L, "type", anchor->type, anchorclass_type_enum);
1478     /*   uint8 has_base; */
1479     /*  uint8 processed, has_mark, matches, ac_num; */
1480     /*  uint8 ticked; */
1481 }
1482 
handle_anchorclass(lua_State * L,struct anchorclass * anchor)1483 void handle_anchorclass(lua_State * L, struct anchorclass *anchor)
1484 {
1485     struct anchorclass *next;
1486     NESTED_TABLE(do_handle_anchorclass, anchor, 10);
1487 }
1488 
do_handle_ttf_table(lua_State * L,struct ttf_table * ttf_tab)1489 void do_handle_ttf_table(lua_State * L, struct ttf_table *ttf_tab)
1490 {
1491 
1492     dump_tag(L, "tag", ttf_tab->tag);
1493     dump_intfield(L, "len", ttf_tab->len);
1494     dump_intfield(L, "maxlen", ttf_tab->maxlen);
1495     dump_lstringfield(L, "data", (char *) ttf_tab->data, ttf_tab->len);
1496 }
1497 
handle_ttf_table(lua_State * L,struct ttf_table * ttf_tab)1498 void handle_ttf_table(lua_State * L, struct ttf_table *ttf_tab)
1499 {
1500     struct ttf_table *next;
1501     NESTED_TABLE(do_handle_ttf_table, ttf_tab, 4);
1502 }
1503 
do_handle_kernclass(lua_State * L,struct kernclass * kerns,const char * name)1504 int do_handle_kernclass(lua_State * L, struct kernclass *kerns, const char *name)
1505 {
1506     int k;
1507     int match = 0;
1508     if (name) {
1509 	struct lookup_subtable *s = kerns->subtable;
1510 	while (s != NULL) {
1511 	    if (strcmp(s->subtable_name,name)==0) {
1512 		match = 1;
1513 		break;
1514 	    }
1515             s = s->next;
1516 	}
1517     } else {
1518 	match = 1;
1519     }
1520     if (!match) {
1521 	return 0;
1522     }
1523     lua_checkstack(L, 4);
1524     lua_createtable(L, kerns->first_cnt, 1);
1525     for (k = 0; k < kerns->first_cnt; k++) {
1526         lua_pushnumber(L, (k + 1));
1527         lua_pushstring(L, kerns->firsts[k]);
1528         lua_rawset(L, -3);
1529     }
1530     lua_setfield(L, -2, "firsts");
1531 
1532     lua_createtable(L, kerns->second_cnt, 1);
1533     for (k = 0; k < kerns->second_cnt; k++) {
1534         lua_pushnumber(L, (k + 1));
1535         lua_pushstring(L, kerns->seconds[k]);
1536         lua_rawset(L, -3);
1537     }
1538     lua_setfield(L, -2, "seconds");
1539 
1540     if (!name) {
1541 	dump_subtable_name(L, "lookup", kerns->subtable);
1542     }
1543 
1544     lua_createtable(L, kerns->second_cnt * kerns->first_cnt, 1);
1545     for (k = 0; k < (kerns->second_cnt * kerns->first_cnt); k++) {
1546         if (kerns->offsets[k] != 0) {
1547             lua_pushnumber(L, (k + 1));
1548             lua_pushnumber(L, kerns->offsets[k]);
1549             lua_rawset(L, -3);
1550         }
1551     }
1552     lua_setfield(L, -2, "offsets");
1553     return 1;
1554 }
1555 
handle_kernclass(lua_State * L,struct kernclass * kerns,const char * name)1556 void handle_kernclass(lua_State * L, struct kernclass *kerns, const char *name)
1557 {
1558     struct kernclass *next;
1559     NESTED_TABLE_SF(do_handle_kernclass, kerns, name, 8);
1560 }
1561 
1562 
1563 #define DUMP_NUMBER_ARRAY(s,cnt,item) {					\
1564     if (cnt>0 && item != NULL) {						\
1565       int kk;											\
1566       lua_newtable(L);									\
1567       for (kk=0;kk<cnt;kk++) {							\
1568 		lua_pushnumber(L,(kk+1));						\
1569 		lua_pushnumber(L,item[kk]);						\
1570 		lua_rawset(L,-3); }								\
1571       lua_setfield(L,-2,s); } }
1572 
1573 
1574 #define DUMP_STRING_ARRAY(s,cnt,item) {				\
1575     if (cnt>0 && item!=NULL) {						\
1576       int kk;										\
1577       lua_newtable(L);								\
1578       for (kk=0;kk<cnt;kk++) {						\
1579 		lua_pushnumber(L,(kk+1));					\
1580 		lua_pushstring(L,item[kk]);					\
1581 		lua_rawset(L,-3); }							\
1582       lua_setfield(L,-2,s); } }
1583 
1584 #define DUMP_EXACT_STRING_ARRAY(s,cnt,item) {		\
1585     if (cnt>0 && item!=NULL) {						\
1586       int kk;										\
1587       lua_newtable(L);								\
1588       for (kk=0;kk<cnt;kk++) {						\
1589 		lua_pushnumber(L,(kk));						\
1590 		lua_pushstring(L,item[kk]);					\
1591 		lua_rawset(L,-3); }							\
1592       lua_setfield(L,-2,s); } }
1593 
1594 
handle_fpst_rule(lua_State * L,struct fpst_rule * rule,int format)1595 void handle_fpst_rule(lua_State * L, struct fpst_rule *rule, int format)
1596 {
1597     int k;
1598 
1599 
1600     if (format == pst_glyphs) {
1601 
1602         lua_newtable(L);
1603         dump_stringfield(L, "names", rule->u.glyph.names);
1604         dump_stringfield(L, "back", rule->u.glyph.back);
1605         dump_stringfield(L, "fore", rule->u.glyph.fore);
1606         lua_setfield(L, -2, fpossub_format_enum[format]);
1607 
1608     } else if (format == pst_class) {
1609 
1610         lua_newtable(L);
1611         DUMP_NUMBER_ARRAY("current", rule->u.class.ncnt,
1612                           rule->u.class.nclasses);
1613         DUMP_NUMBER_ARRAY("before", rule->u.class.bcnt, rule->u.class.bclasses);
1614         DUMP_NUMBER_ARRAY("after", rule->u.class.fcnt, rule->u.class.fclasses);
1615 #if 0
1616         DUMP_NUMBER_ARRAY("allclasses", 0, rule->u.class.allclasses);
1617 #endif
1618         lua_setfield(L, -2, fpossub_format_enum[format]);
1619 
1620     } else if (format == pst_coverage) {
1621 
1622         lua_newtable(L);
1623         DUMP_STRING_ARRAY("current", rule->u.coverage.ncnt,
1624                           rule->u.coverage.ncovers);
1625         DUMP_STRING_ARRAY("before", rule->u.coverage.bcnt,
1626                           rule->u.coverage.bcovers);
1627         DUMP_STRING_ARRAY("after", rule->u.coverage.fcnt,
1628                           rule->u.coverage.fcovers);
1629         lua_setfield(L, -2, fpossub_format_enum[format]);
1630 
1631     } else if (format == pst_reversecoverage) {
1632 
1633         lua_newtable(L);
1634         DUMP_STRING_ARRAY("current", rule->u.rcoverage.always1,
1635                           rule->u.rcoverage.ncovers);
1636         DUMP_STRING_ARRAY("before", rule->u.rcoverage.bcnt,
1637                           rule->u.rcoverage.bcovers);
1638         DUMP_STRING_ARRAY("after", rule->u.rcoverage.fcnt,
1639                           rule->u.rcoverage.fcovers);
1640         dump_stringfield(L, "replacements", rule->u.rcoverage.replacements);
1641         lua_setfield(L, -2, fpossub_format_enum[format]);
1642     } else {
1643         fprintf(stderr, "handle_fpst_rule(): Unknown rule format: %d\n",
1644                 format);
1645     }
1646 
1647     if (rule->lookup_cnt > 0) {
1648         lua_newtable(L);
1649         for (k = 0; k < rule->lookup_cnt; k++) {
1650             lua_pushnumber(L, (rule->lookups[k].seq + 1));
1651             if (rule->lookups[k].lookup != NULL) {
1652                 lua_pushstring(L, rule->lookups[k].lookup->lookup_name);
1653             } else {
1654                 lua_pushnil(L);
1655             }
1656             lua_rawset(L, -3);
1657         }
1658         lua_setfield(L, -2, "lookups");
1659     } else {
1660         /*fprintf(stderr,"handle_fpst_rule(): No lookups?\n"); */
1661     }
1662 }
1663 
do_handle_generic_fpst(lua_State * L,struct generic_fpst * fpst)1664 void do_handle_generic_fpst(lua_State * L, struct generic_fpst *fpst)
1665 {
1666     int k;
1667 
1668     if (fpst->type > LAST_POSSUB_TYPE_ENUM) {
1669         dump_intfield(L, "type", fpst->type);
1670     } else {
1671         dump_enumfield(L, "type", fpst->type, possub_type_enum);
1672     }
1673     dump_enumfield(L, "format", fpst->format, fpossub_format_enum);
1674 
1675     if (fpst->format == pst_class) {
1676         DUMP_EXACT_STRING_ARRAY("current_class", fpst->nccnt, fpst->nclass);
1677         DUMP_EXACT_STRING_ARRAY("before_class", fpst->bccnt, fpst->bclass);
1678         DUMP_EXACT_STRING_ARRAY("after_class", fpst->fccnt, fpst->fclass);
1679     } else {
1680         DUMP_STRING_ARRAY("current_class", fpst->nccnt, fpst->nclass);
1681         DUMP_STRING_ARRAY("before_class", fpst->bccnt, fpst->bclass);
1682         DUMP_STRING_ARRAY("after_class", fpst->fccnt, fpst->fclass);
1683     }
1684 
1685     lua_checkstack(L, 4);
1686     if (fpst->rule_cnt > 0) {
1687         lua_createtable(L, fpst->rule_cnt, 1);
1688         for (k = 0; k < fpst->rule_cnt; k++) {
1689             lua_pushnumber(L, (k + 1));
1690             lua_newtable(L);
1691             handle_fpst_rule(L, &(fpst->rules[k]), fpst->format);
1692             lua_rawset(L, -3);
1693         }
1694         lua_setfield(L, -2, "rules");
1695     }
1696     /*dump_intfield (L,"ticked", fpst->ticked); */
1697 }
1698 
handle_generic_fpst(lua_State * L,struct generic_fpst * fpst)1699 void handle_generic_fpst(lua_State * L, struct generic_fpst *fpst)
1700 {
1701     struct generic_fpst *next;
1702     int k = 1;
1703     lua_checkstack(L, 3);
1704     if (fpst->subtable != NULL && fpst->subtable->subtable_name != NULL) {
1705         lua_pushstring(L, fpst->subtable->subtable_name);
1706     } else {
1707         lua_pushnumber(L, k);
1708         k++;
1709     }
1710     lua_createtable(L, 0, 10);
1711     do_handle_generic_fpst(L, fpst);
1712     lua_rawset(L, -3);
1713     next = fpst->next;
1714     while (next != NULL) {
1715         lua_checkstack(L, 3);
1716         if (next->subtable != NULL && next->subtable->subtable_name != NULL) {
1717             lua_pushstring(L, next->subtable->subtable_name);
1718         } else {
1719             lua_pushnumber(L, k);
1720             k++;
1721         }
1722         lua_createtable(L, 0, 10);
1723         do_handle_generic_fpst(L, next);
1724         lua_rawset(L, -3);
1725         next = next->next;
1726     }
1727 }
1728 
do_handle_otfname(lua_State * L,struct otfname * oname)1729 void do_handle_otfname(lua_State * L, struct otfname *oname)
1730 {
1731     dump_intfield(L, "lang", oname->lang);
1732     dump_stringfield(L, "name", oname->name);
1733 }
1734 
handle_otfname(lua_State * L,struct otfname * oname)1735 void handle_otfname(lua_State * L, struct otfname *oname)
1736 {
1737     struct otfname *next;
1738     NESTED_TABLE(do_handle_otfname, oname, 2);
1739 }
1740 
1741 
1742 
1743 
handle_MATH(lua_State * L,struct MATH * MATH)1744 void handle_MATH(lua_State * L, struct MATH *MATH)
1745 {
1746     dump_intfield(L, "ScriptPercentScaleDown", MATH->ScriptPercentScaleDown);
1747     dump_intfield(L, "ScriptScriptPercentScaleDown",
1748                   MATH->ScriptScriptPercentScaleDown);
1749     dump_intfield(L, "DelimitedSubFormulaMinHeight",
1750                   MATH->DelimitedSubFormulaMinHeight);
1751     dump_intfield(L, "DisplayOperatorMinHeight",
1752                   MATH->DisplayOperatorMinHeight);
1753     dump_intfield(L, "MathLeading", MATH->MathLeading);
1754     dump_intfield(L, "AxisHeight", MATH->AxisHeight);
1755     dump_intfield(L, "AccentBaseHeight", MATH->AccentBaseHeight);
1756     dump_intfield(L, "FlattenedAccentBaseHeight",
1757                   MATH->FlattenedAccentBaseHeight);
1758     dump_intfield(L, "SubscriptShiftDown", MATH->SubscriptShiftDown);
1759     dump_intfield(L, "SubscriptTopMax", MATH->SubscriptTopMax);
1760     dump_intfield(L, "SubscriptBaselineDropMin",
1761                   MATH->SubscriptBaselineDropMin);
1762     dump_intfield(L, "SuperscriptShiftUp", MATH->SuperscriptShiftUp);
1763     dump_intfield(L, "SuperscriptShiftUpCramped",
1764                   MATH->SuperscriptShiftUpCramped);
1765     dump_intfield(L, "SuperscriptBottomMin", MATH->SuperscriptBottomMin);
1766     dump_intfield(L, "SuperscriptBaselineDropMax",
1767                   MATH->SuperscriptBaselineDropMax);
1768     dump_intfield(L, "SubSuperscriptGapMin", MATH->SubSuperscriptGapMin);
1769     dump_intfield(L, "SuperscriptBottomMaxWithSubscript",
1770                   MATH->SuperscriptBottomMaxWithSubscript);
1771     dump_intfield(L, "SpaceAfterScript", MATH->SpaceAfterScript);
1772     dump_intfield(L, "UpperLimitGapMin", MATH->UpperLimitGapMin);
1773     dump_intfield(L, "UpperLimitBaselineRiseMin",
1774                   MATH->UpperLimitBaselineRiseMin);
1775     dump_intfield(L, "LowerLimitGapMin", MATH->LowerLimitGapMin);
1776     dump_intfield(L, "LowerLimitBaselineDropMin",
1777                   MATH->LowerLimitBaselineDropMin);
1778     dump_intfield(L, "StackTopShiftUp", MATH->StackTopShiftUp);
1779     dump_intfield(L, "StackTopDisplayStyleShiftUp",
1780                   MATH->StackTopDisplayStyleShiftUp);
1781     dump_intfield(L, "StackBottomShiftDown", MATH->StackBottomShiftDown);
1782     dump_intfield(L, "StackBottomDisplayStyleShiftDown",
1783                   MATH->StackBottomDisplayStyleShiftDown);
1784     dump_intfield(L, "StackGapMin", MATH->StackGapMin);
1785     dump_intfield(L, "StackDisplayStyleGapMin", MATH->StackDisplayStyleGapMin);
1786     dump_intfield(L, "StretchStackTopShiftUp", MATH->StretchStackTopShiftUp);
1787     dump_intfield(L, "StretchStackBottomShiftDown",
1788                   MATH->StretchStackBottomShiftDown);
1789     dump_intfield(L, "StretchStackGapAboveMin", MATH->StretchStackGapAboveMin);
1790     dump_intfield(L, "StretchStackGapBelowMin", MATH->StretchStackGapBelowMin);
1791     dump_intfield(L, "FractionNumeratorShiftUp",
1792                   MATH->FractionNumeratorShiftUp);
1793     dump_intfield(L, "FractionNumeratorDisplayStyleShiftUp",
1794                   MATH->FractionNumeratorDisplayStyleShiftUp);
1795     dump_intfield(L, "FractionDenominatorShiftDown",
1796                   MATH->FractionDenominatorShiftDown);
1797     dump_intfield(L, "FractionDenominatorDisplayStyleShiftDown",
1798                   MATH->FractionDenominatorDisplayStyleShiftDown);
1799     dump_intfield(L, "FractionNumeratorGapMin", MATH->FractionNumeratorGapMin);
1800     dump_intfield(L, "FractionNumeratorDisplayStyleGapMin",
1801                   MATH->FractionNumeratorDisplayStyleGapMin);
1802     dump_intfield(L, "FractionRuleThickness", MATH->FractionRuleThickness);
1803     dump_intfield(L, "FractionDenominatorGapMin",
1804                   MATH->FractionDenominatorGapMin);
1805     dump_intfield(L, "FractionDenominatorDisplayStyleGapMin",
1806                   MATH->FractionDenominatorDisplayStyleGapMin);
1807     dump_intfield(L, "SkewedFractionHorizontalGap",
1808                   MATH->SkewedFractionHorizontalGap);
1809     dump_intfield(L, "SkewedFractionVerticalGap",
1810                   MATH->SkewedFractionVerticalGap);
1811     dump_intfield(L, "OverbarVerticalGap", MATH->OverbarVerticalGap);
1812     dump_intfield(L, "OverbarRuleThickness", MATH->OverbarRuleThickness);
1813     dump_intfield(L, "OverbarExtraAscender", MATH->OverbarExtraAscender);
1814     dump_intfield(L, "UnderbarVerticalGap", MATH->UnderbarVerticalGap);
1815     dump_intfield(L, "UnderbarRuleThickness", MATH->UnderbarRuleThickness);
1816     dump_intfield(L, "UnderbarExtraDescender", MATH->UnderbarExtraDescender);
1817     dump_intfield(L, "RadicalVerticalGap", MATH->RadicalVerticalGap);
1818     dump_intfield(L, "RadicalDisplayStyleVerticalGap",
1819                   MATH->RadicalDisplayStyleVerticalGap);
1820     dump_intfield(L, "RadicalRuleThickness", MATH->RadicalRuleThickness);
1821     dump_intfield(L, "RadicalExtraAscender", MATH->RadicalExtraAscender);
1822     dump_intfield(L, "RadicalKernBeforeDegree", MATH->RadicalKernBeforeDegree);
1823     dump_intfield(L, "RadicalKernAfterDegree", MATH->RadicalKernAfterDegree);
1824     dump_intfield(L, "RadicalDegreeBottomRaisePercent",
1825                   MATH->RadicalDegreeBottomRaisePercent);
1826     dump_intfield(L, "MinConnectorOverlap", MATH->MinConnectorOverlap);
1827 }
1828 
1829 /* the handling of BASE is untested, no font */
1830 void handle_baselangextent(lua_State * L, struct baselangextent *ble);
1831 
do_handle_baselangextent(lua_State * L,struct baselangextent * ble)1832 void do_handle_baselangextent(lua_State * L, struct baselangextent *ble)
1833 {
1834     dump_tag(L, "tag", ble->lang);
1835     dump_intfield(L, "ascent", ble->ascent);
1836     dump_intfield(L, "descent", ble->descent);
1837     lua_newtable(L);
1838     handle_baselangextent(L, ble->features);
1839     lua_setfield(L, -2, "features");
1840 }
1841 
1842 
handle_baselangextent(lua_State * L,struct baselangextent * ble)1843 void handle_baselangextent(lua_State * L, struct baselangextent *ble)
1844 {
1845     struct baselangextent *next;
1846     NESTED_TABLE(do_handle_baselangextent, ble, 4);
1847 }
1848 
1849 
handle_base(lua_State * L,struct Base * Base)1850 void handle_base(lua_State * L, struct Base *Base)
1851 {
1852     int i;
1853     struct basescript *next = Base->scripts;
1854     lua_newtable(L);
1855     for (i = 0; i < Base->baseline_cnt; i++) {
1856         lua_pushstring(L, make_tag_string(Base->baseline_tags[i]));
1857         lua_rawseti(L, -2, (i + 1));
1858     }
1859     lua_setfield(L, -2, "tags");
1860     if (next != NULL) {
1861         lua_newtable(L);
1862         while (next != NULL) {
1863             lua_pushstring(L, make_tag_string(next->script));
1864             lua_newtable(L);
1865             dump_intfield(L, "default_baseline", (next->def_baseline + 1));
1866             lua_newtable(L);
1867             for (i = 0; i < Base->baseline_cnt; i++) {
1868                 if (next->baseline_pos != NULL) /* default omitted */
1869                     lua_pushnumber(L, next->baseline_pos[i]);
1870                 else
1871                     lua_pushnumber(L, 0);
1872                 lua_rawseti(L, -2, (i + 1));
1873             }
1874             lua_setfield(L, -2, "baseline");
1875             lua_newtable(L);
1876             handle_baselangextent(L, next->langs);
1877             lua_setfield(L, -2, "lang");
1878             lua_rawset(L, -3);
1879             next = next->next;
1880         }
1881         lua_setfield(L, -2, "scripts");
1882     }
1883 }
1884 
1885 
handle_axismap(lua_State * L,struct axismap * am)1886 void handle_axismap(lua_State * L, struct axismap *am)
1887 {
1888     int i;
1889     lua_checkstack(L, 3);
1890     lua_newtable(L);
1891     for (i = 0; i < am->points; i++) {
1892         lua_pushnumber(L, am->blends[i]);
1893         lua_rawseti(L, -2, (i + 1));
1894     }
1895     lua_setfield(L, -2, "blends");
1896     lua_newtable(L);
1897     for (i = 0; i < am->points; i++) {
1898         lua_pushnumber(L, am->designs[i]);
1899         lua_rawseti(L, -2, (i + 1));
1900     }
1901     lua_setfield(L, -2, "designs");
1902     dump_realfield(L, "min", am->min);
1903     dump_realfield(L, "def", am->def);
1904     dump_realfield(L, "max", am->max);
1905 }
1906 
1907 
handle_mmset(lua_State * L,struct mmset * mm)1908 void handle_mmset(lua_State * L, struct mmset *mm)
1909 {
1910     int i, k;
1911     lua_newtable(L);
1912     for (i = 0; i < mm->axis_count; i++) {
1913         lua_pushstring(L, mm->axes[i]);
1914         lua_rawseti(L, -2, (i + 1));
1915     }
1916     lua_setfield(L, -2, "axes");
1917 
1918     dump_intfield(L, "instance_count", mm->instance_count);
1919     /* SplineFont *normal; *//* this is the parent */
1920     if (mm->instance_count > 0) {
1921         lua_newtable(L);
1922         for (i = 0; i < mm->instance_count * mm->axis_count; i++) {
1923             lua_pushnumber(L, mm->positions[i]);
1924             lua_rawseti(L, -2, (i + 1));
1925         }
1926         lua_setfield(L, -2, "positions");
1927 
1928         /* better not to do this */
1929 #if 0
1930         {
1931             struct mmset *mmsave;
1932             lua_newtable(L);
1933             for (i = 0; i < mm->instance_count; i++) {
1934                 lua_checkstack(L, 20);
1935                 lua_createtable(L, 0, 60);
1936                 mmsave = mm->instances[i]->mm;
1937                 mm->instances[i]->mm = NULL;
1938                 handle_splinefont(L, mm->instances[i]);
1939                 mm->instances[i]->mm = mmsave;
1940                 lua_rawseti(L, -2, (i + 1));
1941             }
1942             lua_setfield(L, -2, "instances");
1943         }
1944 #endif
1945 
1946         lua_newtable(L);
1947         for (i = 0; i < mm->instance_count; i++) {
1948             lua_pushnumber(L, mm->defweights[i]);
1949             lua_rawseti(L, -2, (i + 1));
1950         }
1951         lua_setfield(L, -2, "defweights");
1952     }
1953 
1954     if (mm->axismaps != NULL) {
1955         lua_newtable(L);
1956         for (i = 0; i < mm->axis_count; i++) {
1957             lua_newtable(L);
1958             handle_axismap(L, &(mm->axismaps[i]));
1959             lua_rawseti(L, -2, (i + 1));
1960         }
1961         lua_setfield(L, -2, "axismaps");
1962     }
1963     dump_stringfield(L, "cdv", mm->cdv);
1964     dump_stringfield(L, "ndv", mm->ndv);
1965 }
1966 
1967 
1968 
handle_splinefont(lua_State * L,struct splinefont * sf)1969 void handle_splinefont(lua_State * L, struct splinefont *sf)
1970 {
1971     int k;
1972     int fix_notdef = 0;
1973     int l = -1;
1974 
1975     dump_stringfield(L, "table_version", LUA_OTF_VERSION);
1976     dump_stringfield(L, "fontname", sf->fontname);
1977     dump_stringfield(L, "fullname", sf->fullname);
1978     dump_stringfield(L, "familyname", sf->familyname);
1979     dump_stringfield(L, "weight", sf->weight);
1980     dump_stringfield(L, "copyright", sf->copyright);
1981     dump_stringfield(L, "filename", sf->filename);
1982     /* dump_stringfield(L,"defbasefilename", sf->defbasefilename); */
1983     dump_stringfield(L, "version", sf->version);
1984     dump_floatfield(L, "italicangle", sf->italicangle);
1985     dump_floatfield(L, "upos", sf->upos);
1986     dump_floatfield(L, "uwidth", sf->uwidth);
1987     dump_intfield(L, "ascent", sf->ascent);
1988     dump_intfield(L, "descent", sf->descent);
1989     if (sf->uniqueid!=0) {
1990 	dump_intfield(L, "uniqueid", sf->uniqueid);
1991     }
1992     dump_intfield(L, "glyphcnt", sf->glyphcnt);
1993     dump_intfield(L, "glyphmax", sf->glyphmax);
1994     dump_intfield(L, "units_per_em", sf->units_per_em);
1995 
1996     if (sf->possub != NULL) {
1997         lua_newtable(L);
1998         handle_generic_fpst(L, sf->possub);
1999         lua_setfield(L, -2, "lookups");
2000     }
2001 
2002     lua_checkstack(L, 4);
2003     lua_createtable(L, sf->glyphcnt, 0);
2004 
2005     /* This after-the-fact type discovery is not brilliant,
2006        I should really add a 'format' key in the structure */
2007     if ((sf->origname != NULL) &&
2008         (strmatch(sf->origname + strlen(sf->origname) - 4, ".pfa") == 0 ||
2009          strmatch(sf->origname + strlen(sf->origname) - 4, ".pfb") == 0)) {
2010         fix_notdef = 1;
2011     }
2012 
2013     if (fix_notdef) {
2014         /* some code to ensure that the .notdef ends up in slot 0
2015            (this will actually be enforced by the CFF writer) */
2016         for (k = 0; k < sf->glyphcnt; k++) {
2017             if (sf->glyphs[k]) {
2018                 if (strcmp(sf->glyphs[k]->name, ".notdef") == 0) {
2019                     l = k;
2020                 }
2021             }
2022         }
2023         if (l == -1) {          /* fake a .notdef at the end */
2024             l = sf->glyphcnt;
2025         }
2026         for (k = 0; k < l; k++) {
2027             if (sf->glyphs[k]) {
2028                 lua_pushnumber(L, (k + 1));
2029                 lua_createtable(L, 0, 12);
2030                 handle_splinechar(L, sf->glyphs[k], sf->hasvmetrics);
2031                 lua_rawset(L, -3);
2032             }
2033         }
2034         if (sf->glyphs != NULL && l < sf->glyphcnt) {
2035             lua_pushnumber(L, 0);
2036             if (sf->glyphs[l]) {
2037                 lua_createtable(L, 0, 12);
2038                 handle_splinechar(L, sf->glyphs[l], sf->hasvmetrics);
2039             } else {
2040                 lua_createtable(L, 0, 0);
2041             }
2042             lua_rawset(L, -3);
2043         }
2044     }
2045     if ((l + 1) < sf->glyphcnt) {
2046         for (k = (l + 1); k < sf->glyphcnt; k++) {
2047             if (sf->glyphs[k]) {
2048                 lua_pushnumber(L, k);
2049                 lua_createtable(L, 0, 12);
2050                 handle_splinechar(L, sf->glyphs[k], sf->hasvmetrics);
2051                 lua_rawset(L, -3);
2052             }
2053         }
2054     }
2055     lua_setfield(L, -2, "glyphs");
2056 
2057     /* dump_intfield(L,"changed",                   sf->changed); */
2058     dump_intfield(L, "hasvmetrics", sf->hasvmetrics);
2059     dump_intfield(L, "onlybitmaps", sf->onlybitmaps);
2060     dump_intfield(L, "serifcheck", sf->serifcheck);
2061     dump_intfield(L, "isserif", sf->isserif);
2062     dump_intfield(L, "issans", sf->issans);
2063     dump_intfield(L, "encodingchanged", sf->encodingchanged);
2064     dump_intfield(L, "strokedfont", sf->strokedfont);
2065     dump_intfield(L, "use_typo_metrics", sf->use_typo_metrics);
2066     dump_intfield(L, "weight_width_slope_only", sf->weight_width_slope_only);
2067     dump_intfield(L, "head_optimized_for_cleartype",
2068                   sf->head_optimized_for_cleartype);
2069 
2070     dump_enumfield(L, "uni_interp", (sf->uni_interp + 1), uni_interp_enum);
2071 
2072     if (sf->map != NULL) {
2073         lua_newtable(L);
2074         handle_encmap(L, sf->map, l);
2075         lua_setfield(L, -2, "map");
2076     }
2077 
2078     dump_stringfield(L, "origname", sf->origname);      /* new */
2079 
2080     if (sf->private != NULL) {
2081         lua_newtable(L);
2082         handle_psdict(L, sf->private);
2083         lua_setfield(L, -2, "private");
2084     }
2085 
2086     dump_stringfield(L, "xuid", sf->xuid);
2087 
2088     lua_createtable(L, 0, 40);
2089     handle_pfminfo(L, sf->pfminfo);
2090     lua_setfield(L, -2, "pfminfo");
2091 
2092     if (sf->names != NULL) {
2093         lua_newtable(L);
2094         handle_ttflangname(L, sf->names);
2095         lua_setfield(L, -2, "names");
2096     }
2097 
2098     lua_createtable(L, 0, 4);
2099     dump_stringfield(L, "registry", sf->cidregistry);
2100     dump_stringfield(L, "ordering", sf->ordering);
2101     dump_intfield(L, "version", sf->cidversion);
2102     dump_intfield(L, "supplement", sf->supplement);
2103     lua_setfield(L, -2, "cidinfo");
2104 
2105     /* SplineFont *cidmaster *//* parent in a subfont */
2106     if (sf->subfontcnt > 0) {
2107         lua_createtable(L, sf->subfontcnt, 0);
2108         for (k = 0; k < sf->subfontcnt; k++) {
2109             lua_checkstack(L, 10);
2110             lua_newtable(L);
2111             handle_splinefont(L, sf->subfonts[k]);
2112             lua_rawseti(L, -2, (k + 1));
2113         }
2114         lua_setfield(L, -2, "subfonts");
2115     }
2116 
2117     dump_stringfield(L, "comments", sf->comments);
2118     dump_stringfield(L, "fontlog", sf->fontlog);
2119 
2120     if (sf->cvt_names != NULL) {
2121         lua_newtable(L);
2122         for (k = 0; sf->cvt_names[k] != END_CVT_NAMES; ++k) {
2123             lua_pushstring(L, sf->cvt_names[k]);
2124             lua_rawseti(L, -2, (k + 1));
2125         }
2126         lua_setfield(L, -2, "cvt_names");
2127     }
2128 
2129     if (sf->ttf_tables != NULL) {
2130         lua_newtable(L);
2131         handle_ttf_table(L, sf->ttf_tables);
2132         lua_setfield(L, -2, "ttf_tables");
2133     }
2134 
2135     if (sf->ttf_tab_saved != NULL) {
2136         lua_newtable(L);
2137         handle_ttf_table(L, sf->ttf_tab_saved);
2138         lua_setfield(L, -2, "ttf_tab_saved");
2139     }
2140 
2141     if (sf->texdata.type != tex_unset) {
2142         lua_newtable(L);
2143         dump_enumfield(L, "type", sf->texdata.type, tex_type_enum);
2144         lua_newtable(L);
2145         for (k = 0; k < 22; k++) {
2146             lua_pushnumber(L, k);
2147             lua_pushnumber(L, sf->texdata.params[k]);
2148             lua_rawset(L, -3);
2149         }
2150         lua_setfield(L, -2, "params");
2151         lua_setfield(L, -2, "texdata");
2152     }
2153     if (sf->anchor != NULL) {
2154         lua_newtable(L);
2155         handle_anchorclass(L, sf->anchor);
2156         lua_setfield(L, -2, "anchor_classes");
2157     }
2158     if (sf->kerns != NULL) {
2159         lua_newtable(L);
2160         handle_kernclass(L, sf->kerns, NULL);
2161         lua_setfield(L, -2, "kerns");
2162     }
2163     if (sf->vkerns != NULL) {
2164         lua_newtable(L);
2165         handle_kernclass(L, sf->vkerns, NULL);
2166         lua_setfield(L, -2, "vkerns");
2167     }
2168     if (sf->gsub_lookups != NULL) {
2169         lua_newtable(L);
2170         handle_lookup(L, sf->gsub_lookups, sf);
2171         lua_setfield(L, -2, "gsub");
2172     }
2173     if (sf->gpos_lookups != NULL) {
2174         lua_newtable(L);
2175         handle_lookup(L, sf->gpos_lookups, sf);
2176         lua_setfield(L, -2, "gpos");
2177     }
2178 
2179     if (sf->mm != NULL) {
2180         lua_newtable(L);
2181         handle_mmset(L, sf->mm);
2182         lua_setfield(L, -2, "mm");
2183     }
2184     dump_stringfield(L, "chosenname", sf->chosenname);
2185 
2186     if (sf->macstyle!=-1) {
2187 	dump_intfield(L, "macstyle", sf->macstyle);
2188     }
2189     dump_stringfield(L, "fondname", sf->fondname);
2190 
2191     dump_intfield(L, "design_size", sf->design_size);
2192     dump_intfield(L, "fontstyle_id", sf->fontstyle_id);
2193 
2194     if (sf->fontstyle_name != NULL) {
2195         lua_newtable(L);
2196         handle_otfname(L, sf->fontstyle_name);
2197         lua_setfield(L, -2, "fontstyle_name");
2198     }
2199 
2200     dump_intfield(L, "design_range_bottom", sf->design_range_bottom);
2201     dump_intfield(L, "design_range_top", sf->design_range_top);
2202     dump_floatfield(L, "strokewidth", sf->strokewidth);
2203 
2204     if (sf->mark_class_cnt > 0) {
2205         lua_newtable(L);
2206         for (k = 0; k < sf->mark_class_cnt; k++) {
2207             if (sf->mark_class_names[k] != NULL) {
2208                 lua_pushstring(L, sf->mark_class_names[k]);
2209                 lua_pushstring(L, sf->mark_classes[k]);
2210                 lua_rawset(L, -3);
2211             }
2212         }
2213         lua_setfield(L, -2, "mark_classes");
2214     }
2215 
2216     dump_uintfield(L, "creationtime", sf->creationtime);
2217     dump_uintfield(L, "modificationtime", sf->modificationtime);
2218 
2219     dump_intfield(L, "os2_version", sf->os2_version);
2220     dump_intfield(L, "sfd_version", sf->sfd_version);
2221 
2222     if (sf->MATH != NULL) {
2223         lua_newtable(L);
2224         handle_MATH(L, sf->MATH);
2225         lua_setfield(L, -2, "math");
2226     }
2227 
2228     if (sf->loadvalidation_state != 0) {
2229         int val, st;
2230         lua_newtable(L);
2231         val = 1;
2232         st = sf->loadvalidation_state;
2233         if (st & lvs_bad_ps_fontname) {
2234             lua_pushliteral(L, "bad_ps_fontname");
2235             lua_rawseti(L, -2, val++);
2236         }
2237         if (st & lvs_bad_glyph_table) {
2238             lua_pushliteral(L, "bad_glyph_table");
2239             lua_rawseti(L, -2, val++);
2240         }
2241         if (st & lvs_bad_cff_table) {
2242             lua_pushliteral(L, "bad_cff_table");
2243             lua_rawseti(L, -2, val++);
2244         }
2245         if (st & lvs_bad_metrics_table) {
2246             lua_pushliteral(L, "bad_metrics_table");
2247             lua_rawseti(L, -2, val++);
2248         }
2249         if (st & lvs_bad_cmap_table) {
2250             lua_pushliteral(L, "bad_cmap_table");
2251             lua_rawseti(L, -2, val++);
2252         }
2253         if (st & lvs_bad_bitmaps_table) {
2254             lua_pushliteral(L, "bad_bitmaps_table");
2255             lua_rawseti(L, -2, val++);
2256         }
2257         if (st & lvs_bad_gx_table) {
2258             lua_pushliteral(L, "bad_gx_table");
2259             lua_rawseti(L, -2, val++);
2260         }
2261         if (st & lvs_bad_ot_table) {
2262             lua_pushliteral(L, "bad_ot_table");
2263             lua_rawseti(L, -2, val++);
2264         }
2265         if (st & lvs_bad_os2_version) {
2266             lua_pushliteral(L, "bad_os2_version");
2267             lua_rawseti(L, -2, val++);
2268         }
2269         if (st & lvs_bad_sfnt_header) {
2270             lua_pushliteral(L, "bad_sfnt_header");
2271             lua_rawseti(L, -2, val++);
2272         }
2273         lua_setfield(L, -2, "validation_state");
2274     }
2275 
2276     if (sf->horiz_base != NULL) {
2277         lua_newtable(L);
2278         handle_base(L, sf->horiz_base);
2279         lua_setfield(L, -2, "horiz_base");
2280     }
2281     if (sf->vert_base != NULL) {
2282         lua_newtable(L);
2283         handle_base(L, sf->vert_base);
2284         lua_setfield(L, -2, "vert_base");
2285     }
2286     dump_intfield(L, "extrema_bound", sf->extrema_bound);
2287 }
2288 
ff_make_table(lua_State * L)2289 int ff_make_table(lua_State * L)
2290 {
2291     SplineFont *sf;
2292     sf = *(check_isfont(L, 1));
2293     if (sf == NULL) {
2294         lua_pushboolean(L, 0);
2295     } else {
2296         lua_createtable(L, 0, 60);
2297         handle_splinefont(L, sf);
2298     }
2299     return 1;
2300 }
2301 
do_ff_info(lua_State * L,SplineFont * sf)2302 void do_ff_info(lua_State * L, SplineFont * sf)
2303 {
2304     lua_newtable(L);
2305     dump_stringfield(L, "familyname", sf->familyname);
2306     dump_stringfield(L, "fontname", sf->fontname);
2307     dump_stringfield(L, "fullname", sf->fullname);
2308     dump_floatfield(L, "italicangle", sf->italicangle);
2309     dump_stringfield(L, "version", sf->version);
2310     dump_stringfield(L, "weight", sf->weight);
2311 
2312     dump_intfield(L, "units_per_em", sf->units_per_em);
2313     /* These are not assigned in info... */
2314     /*dump_intfield(L, "design_range_bottom", sf->design_range_bottom);*/
2315     /*dump_intfield(L, "design_range_top", sf->design_range_top);*/
2316     /*dump_intfield(L, "design_size", sf->design_size);*/
2317 
2318     lua_createtable(L, 0, 40);
2319     handle_pfminfo(L, sf->pfminfo);
2320     lua_setfield(L, -2, "pfminfo");
2321 
2322     /* Do we need this ? */
2323     if (sf->names != NULL) {
2324          lua_newtable(L);
2325          handle_ttflangname(L, sf->names);
2326          lua_setfield(L, -2, "names");
2327     }
2328 }
2329 
2330 typedef enum {
2331     FK_table_version = 0,
2332     FK_fontname,
2333     FK_fullname,
2334     FK_familyname,
2335     FK_weight,
2336     FK_copyright,
2337     FK_filename,
2338     FK_version,
2339     FK_italicangle,
2340     FK_upos,
2341     FK_uwidth,
2342     FK_ascent,
2343     FK_descent,
2344     FK_uniqueid,
2345     FK_glyphcnt,
2346     FK_glyphmax,
2347     FK_units_per_em,
2348     FK_lookups,
2349     FK_glyphs,
2350     FK_hasvmetrics,
2351     FK_onlybitmaps,
2352     FK_serifcheck,
2353     FK_isserif,
2354     FK_issans,
2355     FK_encodingchanged,
2356     FK_strokedfont,
2357     FK_use_typo_metrics,
2358     FK_weight_width_slope_only,
2359     FK_head_optimized_for_cleartype,
2360     FK_uni_interp,
2361     FK_map,
2362     FK_origname,
2363     FK_private,
2364     FK_xuid,
2365     FK_pfminfo,
2366     FK_names,
2367     FK_cidinfo,
2368     FK_subfonts,
2369     FK_comments,
2370     FK_fontlog,
2371     FK_cvt_names,
2372     FK_ttf_tables,
2373     FK_ttf_tab_saved,
2374     FK_texdata,
2375     FK_anchor_classes,
2376     FK_kerns,
2377     FK_vkerns,
2378     FK_gsub,
2379     FK_gpos,
2380     /* FK_sm, */ /*this was removed because AAT is not supported anymore*/
2381     FK_features,
2382     FK_mm,
2383     FK_chosenname,
2384     FK_macstyle,
2385     FK_fondname,
2386     FK_design_size,
2387     FK_fontstyle_id,
2388     FK_fontstyle_name,
2389     FK_design_range_bottom,
2390     FK_design_range_top,
2391     FK_strokewidth,
2392     FK_mark_classes,
2393     FK_creationtime,
2394     FK_modificationtime,
2395     FK_os2_version,
2396     FK_sfd_version,
2397     FK_math,
2398     FK_validation_state,
2399     FK_horiz_base,
2400     FK_vert_base,
2401     FK_extrema_bound,
2402 } font_key_values;
2403 
2404 const char *font_keys[] = {
2405     "table_version",
2406     "fontname",
2407     "fullname",
2408     "familyname",
2409     "weight",
2410     "copyright",
2411     "filename",
2412     "version",
2413     "italicangle",
2414     "upos",
2415     "uwidth",
2416     "ascent",
2417     "descent",
2418     "uniqueid",
2419     "glyphcnt",
2420     "glyphmax",
2421     "units_per_em",
2422     "lookups",
2423     "glyphs",
2424     "hasvmetrics",
2425     "onlybitmaps",
2426     "serifcheck",
2427     "isserif",
2428     "issans",
2429     "encodingchanged",
2430     "strokedfont",
2431     "use_typo_metrics",
2432     "weight_width_slope_only",
2433     "head_optimized_for_cleartype",
2434     "uni_interp",
2435     "map",
2436     "origname",
2437     "private",
2438     "xuid",
2439     "pfminfo",
2440     "names",
2441     "cidinfo",
2442     "subfonts",
2443     "comments",
2444     "fontlog",
2445     "cvt_names",
2446     "ttf_tables",
2447     "ttf_tab_saved",
2448     "texdata",
2449     "anchor_classes",
2450     "kerns",
2451     "vkerns",
2452     "gsub",
2453     "gpos",
2454     "features",
2455     "mm",
2456     "chosenname",
2457     "macstyle",
2458     "fondname",
2459     "design_size",
2460     "fontstyle_id",
2461     "fontstyle_name",
2462     "design_range_bottom",
2463     "design_range_top",
2464     "strokewidth",
2465     "mark_classes",
2466     "creationtime",
2467     "modificationtime",
2468     "os2_version",
2469     "sfd_version",
2470     "math",
2471     "validation_state",
2472     "horiz_base",
2473     "vert_base",
2474     "extrema_bound",
2475     NULL
2476 };
2477 
2478 
2479 typedef enum {
2480     GK_name = 0,
2481     GK_unicode,
2482     GK_boundingbox,
2483     GK_vwidth,
2484     GK_width,
2485     GK_lsidebearing,
2486     GK_class,
2487     GK_kerns,
2488     GK_vkerns,
2489     GK_dependents,
2490     GK_lookups,
2491     GK_ligatures,
2492     GK_comment,
2493     GK_anchors,
2494     GK_altuni,
2495     GK_tex_height,
2496     GK_tex_depth,
2497     GK_is_extended_shape,
2498     GK_italic_correction,
2499     GK_top_accent,
2500     GK_vert_variants,
2501     GK_horiz_variants,
2502     GK_mathkern,
2503 } font_glyph_key_values;
2504 
2505 const char *font_glyph_keys[] = {
2506     "name",
2507     "unicode",
2508     "boundingbox",
2509     "vwidth",
2510     "width",
2511     "lsidebearing",
2512     "class",
2513     "kerns",
2514     "vkerns",
2515     "dependents",
2516     "lookups",
2517     "ligatures",
2518     "comment",
2519     "anchors",
2520     "altuni",
2521     "tex_height",
2522     "tex_depth",
2523     "is_extended_shape",
2524     "italic_correction",
2525     "top_accent",
2526     "vert_variants",
2527     "horiz_variants",
2528     "mathkern",
2529     NULL
2530 };
2531 
2532 
ff_fields(lua_State * L)2533 static int ff_fields(lua_State * L)
2534 {
2535     int i;
2536     const char **fields = NULL;
2537     if (is_userdata(L, 1, FONT_METATABLE) ||
2538 	is_userdata(L, 1, FONT_SUBFONT_METATABLE)) {
2539         fields = font_keys;
2540     } else if (is_userdata(L, 1, FONT_GLYPH_METATABLE)) {
2541         fields = font_glyph_keys;
2542     }
2543     if (fields != NULL) {
2544         lua_newtable(L);
2545         for (i = 0; fields[i] != NULL; i++) {
2546             lua_pushstring(L, fields[i]);
2547             lua_rawseti(L, -2, (i + 1));
2548         }
2549     } else {
2550         lua_pushnil(L);
2551     }
2552     return 1;
2553 }
2554 
2555 
2556 
ff_glyphs_index(lua_State * L)2557 static int ff_glyphs_index(lua_State * L)
2558 {
2559 
2560     SplineFont *sf;
2561     int gid = 0;
2562     int l = -1;
2563     int fix_notdef = 0;
2564     lua_pushstring(L, "__sf");
2565     lua_rawget(L, 1);
2566     /* sf = *check_isfont(L, -1); */
2567     if (!(is_userdata(L, -1, FONT_METATABLE) ||
2568 	  is_userdata(L, -1, FONT_SUBFONT_METATABLE))) {
2569         return luaL_error(L,
2570                           "fontloader.__index: expected a (sub)font userdata object\n");
2571     }
2572     sf = *((SplineFont **)lua_touserdata(L, -1));
2573 
2574     lua_pop(L, 1);
2575     gid = luaL_checkinteger(L, 2);
2576     if (gid < 0 || gid >= sf->glyphmax) {
2577         return luaL_error(L, "fontloader.glyphs.__index: index is invalid\n");
2578     }
2579     /* This after-the-fact type discovery is not brilliant,
2580        I should really add a 'format' key in the structure */
2581     if ((sf->origname != NULL) &&
2582         (strmatch(sf->origname + strlen(sf->origname) - 4, ".pfa") == 0 ||
2583          strmatch(sf->origname + strlen(sf->origname) - 4, ".pfb") == 0)) {
2584         fix_notdef = 1;
2585     }
2586     /* some code to ensure that the .notdef ends up in slot 0
2587        (this will actually be enforced by the CFF writer) */
2588     if (fix_notdef) {
2589         l = notdef_loc(sf);
2590         /* now l is the .notdef location, adjust gid if needed */
2591         if (l == sf->glyphcnt) {        /* no .notdef at all, will be created at zero */
2592             if (gid == 0) {
2593                 gid = l;        /* .notdef was added at end */
2594             } else {
2595                 gid--;          /* f.glyphs[gid] == sf->glyphs[gid-1] */
2596             }
2597         } else if (l != 0) {
2598             if (gid == 0) {
2599                 gid = l;
2600             } else if (gid < l) {
2601                 gid--;
2602             }
2603         }
2604     }
2605     /* push the glyph */
2606     if (sf->glyphs[gid] && sf->glyphs[gid] != (struct splinechar *)-1) {
2607         lua_ff_pushglyph(L, sf->glyphs[gid]);
2608     } else {
2609 	lua_pushnil(L);
2610     }
2611     return 1;
2612 }
2613 
ff_glyph_index(lua_State * L)2614 static int ff_glyph_index(lua_State * L)
2615 {
2616     struct splinechar *glyph;
2617     int key;
2618     glyph = *check_isglyph(L, 1);
2619     if (glyph == NULL) {
2620         return luaL_error(L,
2621                           "fontloader.glyph.__index: glyph is nonexistent\n");
2622     }
2623     if (!lua_isstring(L, 2)) {  /* 1 == 'font' */
2624         return luaL_error(L,
2625                           "fontloader.glyph.__index: can only be indexed by string\n");
2626     }
2627     key = luaL_checkoption(L, 2, NULL, font_glyph_keys);
2628     switch (key) {
2629     case GK_name:
2630         lua_pushstring(L, glyph->name);
2631         break;
2632     case GK_unicode:
2633         lua_pushnumber(L, glyph->unicodeenc);
2634         break;
2635     case GK_boundingbox:
2636         if (glyph->xmax == 0 && glyph->ymax == 0 && glyph->xmin == 0
2637             && glyph->ymin == 0) {
2638             DBounds bb;
2639             SplineCharFindBounds(glyph, &bb);
2640             glyph->xmin = bb.minx;
2641             glyph->ymin = bb.miny;
2642             glyph->xmax = bb.maxx;
2643             glyph->ymax = bb.maxy;
2644         }
2645         lua_createtable(L, 4, 0);
2646         lua_pushnumber(L, 1);
2647         lua_pushnumber(L, glyph->xmin);
2648         lua_rawset(L, -3);
2649         lua_pushnumber(L, 2);
2650         lua_pushnumber(L, glyph->ymin);
2651         lua_rawset(L, -3);
2652         lua_pushnumber(L, 3);
2653         lua_pushnumber(L, glyph->xmax);
2654         lua_rawset(L, -3);
2655         lua_pushnumber(L, 4);
2656         lua_pushnumber(L, glyph->ymax);
2657         lua_rawset(L, -3);
2658         break;
2659     case GK_vwidth:
2660         lua_pushnumber(L, glyph->vwidth);
2661         break;
2662     case GK_width:
2663         lua_pushnumber(L, glyph->width);
2664         break;
2665     case GK_lsidebearing:
2666         lua_pushnumber(L, glyph->lsidebearing);
2667         break;
2668     case GK_class:
2669         if (glyph->glyph_class > 0) {
2670             lua_pushstring(L, glyph_class_enum[glyph->glyph_class]);
2671         } else {
2672             lua_pushnil(L);
2673         }
2674         break;
2675     case GK_kerns:
2676         if (glyph->kerns != NULL) {
2677             lua_newtable(L);
2678             handle_kernpair(L, glyph->kerns);
2679         } else {
2680             lua_pushnil(L);
2681         }
2682         break;
2683     case GK_vkerns:
2684         if (glyph->vkerns != NULL) {
2685             lua_newtable(L);
2686             handle_kernpair(L, glyph->vkerns);
2687         } else {
2688             lua_pushnil(L);
2689         }
2690         break;
2691     case GK_dependents:
2692         if (glyph->dependents != NULL) {
2693             lua_newtable(L);
2694             handle_splinecharlist(L, glyph->dependents);
2695         } else {
2696             lua_pushnil(L);
2697         }
2698         break;
2699     case GK_lookups:
2700         if (glyph->possub != NULL) {
2701             lua_newtable(L);
2702             handle_generic_pst(L, glyph->possub);
2703         } else {
2704             lua_pushnil(L);
2705         }
2706         break;
2707     case GK_ligatures:
2708         if (glyph->ligofme != NULL) {
2709             lua_newtable(L);
2710             handle_liglist(L, glyph->ligofme);
2711         } else {
2712             lua_pushnil(L);
2713         }
2714         break;
2715     case GK_comment:
2716         lua_pushstring(L, glyph->comment);
2717         break;
2718     case GK_anchors:
2719         if (glyph->anchor != NULL) {
2720             lua_newtable(L);
2721             handle_anchorpoint(L, glyph->anchor);
2722         } else {
2723             lua_pushnil(L);
2724         }
2725         break;
2726     case GK_altuni:
2727         if (glyph->altuni != NULL) {
2728             lua_newtable(L);
2729             handle_altuni(L, glyph->altuni);
2730         } else {
2731             lua_pushnil(L);
2732         }
2733         break;
2734     case GK_tex_height:
2735         if (glyph->tex_height != TEX_UNDEF) {
2736             lua_pushnumber(L, glyph->tex_height);
2737         } else {
2738             lua_pushnil(L);
2739         }
2740         break;
2741     case GK_tex_depth:
2742         if (glyph->tex_height != TEX_UNDEF) {
2743             lua_pushnumber(L, glyph->tex_depth);
2744         } else {
2745             lua_pushnil(L);
2746         }
2747         break;
2748     case GK_is_extended_shape:
2749         lua_pushnumber(L, glyph->is_extended_shape);
2750         break;
2751     case GK_italic_correction:
2752         if (glyph->italic_correction != TEX_UNDEF) {
2753             lua_pushnumber(L, glyph->italic_correction);
2754         } else {
2755             lua_pushnil(L);
2756         }
2757         break;
2758     case GK_top_accent:
2759         if (glyph->top_accent_horiz != TEX_UNDEF) {
2760             lua_pushnumber(L, glyph->top_accent_horiz);
2761         } else {
2762             lua_pushnil(L);
2763         }
2764         break;
2765     case GK_vert_variants:
2766         if (glyph->vert_variants != NULL) {
2767             lua_newtable(L);
2768             handle_glyphvariants(L, glyph->vert_variants);
2769         } else {
2770             lua_pushnil(L);
2771         }
2772         break;
2773     case GK_horiz_variants:
2774         if (glyph->horiz_variants != NULL) {
2775             lua_newtable(L);
2776             handle_glyphvariants(L, glyph->horiz_variants);
2777         } else {
2778             lua_pushnil(L);
2779         }
2780         break;
2781     case GK_mathkern:
2782         if (glyph->mathkern != NULL) {
2783             lua_newtable(L);
2784             handle_mathkern(L, glyph->mathkern);
2785         } else {
2786             lua_pushnil(L);
2787         }
2788         break;
2789     default:
2790         lua_pushnil(L);
2791     }
2792     return 1;
2793 }
2794 
2795 
ff_index(lua_State * L)2796 static int ff_index(lua_State * L)
2797 {
2798     SplineFont *sf;
2799     int k, key;
2800     /* sf = *check_isfont(L, 1); */
2801     if (!(is_userdata(L, 1, FONT_METATABLE) ||
2802 	  is_userdata(L, 1, FONT_SUBFONT_METATABLE))) {
2803         return luaL_error(L,
2804                           "fontloader.__index: expected a (sub)font userdata object\n");
2805     }
2806     sf = *((SplineFont **)lua_touserdata(L, 1));
2807 
2808     if (sf == NULL) {
2809         return luaL_error(L,
2810                           "fontloader.__index: font is nonexistent or freed already\n");
2811     }
2812     if (!lua_isstring(L, 2)) {  /* 1 == 'font' */
2813         return luaL_error(L,
2814                           "fontloader.__index: can only be indexed by string\n");
2815     }
2816     key = luaL_checkoption(L, 2, NULL, font_keys);
2817     switch (key) {
2818     case FK_table_version:
2819         lua_pushstring(L, LUA_OTF_VERSION);
2820         break;
2821     case FK_fontname:
2822         lua_pushstring(L, sf->fontname);
2823         break;
2824     case FK_fullname:
2825         lua_pushstring(L, sf->fullname);
2826         break;
2827     case FK_familyname:
2828         lua_pushstring(L, sf->familyname);
2829         break;
2830     case FK_weight:
2831         lua_pushstring(L, sf->weight);
2832         break;
2833     case FK_copyright:
2834         lua_pushstring(L, sf->copyright);
2835         break;
2836     case FK_filename:
2837         lua_pushstring(L, sf->filename);
2838         break;
2839     case FK_version:
2840         lua_pushstring(L, sf->version);
2841         break;
2842     case FK_italicangle:
2843         lua_pushnumber(L, sf->italicangle);
2844         break;
2845     case FK_upos:
2846         lua_pushnumber(L, sf->upos);
2847         break;
2848     case FK_uwidth:
2849         lua_pushnumber(L, sf->uwidth);
2850         break;
2851     case FK_ascent:
2852         lua_pushnumber(L, sf->ascent);
2853         break;
2854     case FK_descent:
2855         lua_pushnumber(L, sf->descent);
2856         break;
2857     case FK_uniqueid:
2858         lua_pushnumber(L, sf->uniqueid);
2859         break;
2860     case FK_glyphcnt:
2861         lua_pushnumber(L, sf->glyphcnt);
2862         break;
2863     case FK_glyphmax:
2864         lua_pushnumber(L, sf->glyphmax);
2865         break;
2866     case FK_units_per_em:
2867         lua_pushnumber(L, sf->units_per_em);
2868         break;
2869     case FK_lookups:
2870         if (sf->possub != NULL) {
2871             lua_newtable(L);
2872             handle_generic_fpst(L, sf->possub);
2873         } else {
2874             lua_pushnil(L);
2875         }
2876         break;
2877     case FK_glyphs:
2878         lua_newtable(L);        /* the virtual glyph table */
2879         lua_pushstring(L, "__sf");
2880         lua_pushvalue(L, 1);    /* that is our font */
2881         lua_rawset(L, -3);
2882         luaL_getmetatable(L, FONT_GLYPHS_METATABLE);
2883         lua_setmetatable(L, -2);        /* assign the metatable */
2884         break;
2885     case FK_hasvmetrics:
2886         lua_pushnumber(L, sf->hasvmetrics);
2887         break;
2888     case FK_onlybitmaps:
2889         lua_pushnumber(L, sf->onlybitmaps);
2890         break;
2891     case FK_serifcheck:
2892         lua_pushnumber(L, sf->serifcheck);
2893         break;
2894     case FK_isserif:
2895         lua_pushnumber(L, sf->isserif);
2896         break;
2897     case FK_issans:
2898         lua_pushnumber(L, sf->issans);
2899         break;
2900     case FK_encodingchanged:
2901         lua_pushnumber(L, sf->encodingchanged);
2902         break;
2903     case FK_strokedfont:
2904         lua_pushnumber(L, sf->strokedfont);
2905         break;
2906     case FK_use_typo_metrics:
2907         lua_pushnumber(L, sf->use_typo_metrics);
2908         break;
2909     case FK_weight_width_slope_only:
2910         lua_pushnumber(L, sf->weight_width_slope_only);
2911         break;
2912     case FK_head_optimized_for_cleartype:
2913         lua_pushnumber(L, sf->head_optimized_for_cleartype);
2914         break;
2915     case FK_uni_interp:
2916         lua_pushstring(L, uni_interp_enum[(sf->uni_interp + 1)]);
2917         break;
2918     case FK_map:
2919         if (sf->map != NULL) {
2920             lua_newtable(L);
2921             handle_encmap(L, sf->map, notdef_loc(sf));
2922         } else {
2923             lua_pushnil(L);
2924         }
2925         break;
2926     case FK_origname:
2927         lua_pushstring(L, sf->origname);
2928         break;
2929     case FK_private:
2930         if (sf->private != NULL) {
2931             lua_newtable(L);
2932             handle_psdict(L, sf->private);
2933         } else {
2934             lua_pushnil(L);
2935         }
2936         break;
2937     case FK_xuid:
2938         lua_pushstring(L, sf->xuid);
2939         break;
2940     case FK_pfminfo:
2941         lua_createtable(L, 0, 40);
2942         handle_pfminfo(L, sf->pfminfo);
2943         break;
2944     case FK_names:
2945         if (sf->names != NULL) {
2946             lua_newtable(L);
2947             handle_ttflangname(L, sf->names);
2948         } else {
2949             lua_pushnil(L);
2950         }
2951         break;
2952     case FK_cidinfo:
2953         lua_createtable(L, 0, 4);
2954         dump_stringfield(L, "registry", sf->cidregistry);
2955         dump_stringfield(L, "ordering", sf->ordering);
2956         dump_intfield(L, "version", sf->cidversion);
2957         dump_intfield(L, "supplement", sf->supplement);
2958         break;
2959     case FK_subfonts:
2960         if (sf->subfontcnt > 0) {
2961             lua_createtable(L, sf->subfontcnt, 0);
2962             for (k = 0; k < sf->subfontcnt; k++) {
2963                 lua_ff_pushsubfont(L, sf->subfonts[k]);
2964                 lua_rawseti(L, -2, (k + 1));
2965             }
2966         } else {
2967             lua_pushnil(L);
2968         }
2969         break;
2970     case FK_comments:
2971         lua_pushstring(L, sf->comments);
2972         break;
2973     case FK_fontlog:
2974         lua_pushstring(L, sf->fontlog);
2975         break;
2976     case FK_cvt_names:
2977         if (sf->cvt_names != NULL) {
2978             lua_newtable(L);
2979             for (k = 0; sf->cvt_names[k] != END_CVT_NAMES; ++k) {
2980                 lua_pushstring(L, sf->cvt_names[k]);
2981                 lua_rawseti(L, -2, (k + 1));
2982             }
2983         } else {
2984             lua_pushnil(L);
2985         }
2986         break;
2987     case FK_ttf_tables:
2988         if (sf->ttf_tables != NULL) {
2989             lua_newtable(L);
2990             handle_ttf_table(L, sf->ttf_tables);
2991         } else {
2992             lua_pushnil(L);
2993         }
2994         break;
2995     case FK_ttf_tab_saved:
2996         if (sf->ttf_tab_saved != NULL) {
2997             lua_newtable(L);
2998             handle_ttf_table(L, sf->ttf_tab_saved);
2999         } else {
3000             lua_pushnil(L);
3001         }
3002         break;
3003     case FK_texdata:
3004         if (sf->texdata.type != tex_unset) {
3005             lua_newtable(L);
3006             dump_enumfield(L, "type", sf->texdata.type, tex_type_enum);
3007             lua_newtable(L);
3008             for (k = 0; k < 22; k++) {
3009                 lua_pushnumber(L, k);
3010                 lua_pushnumber(L, sf->texdata.params[k]);
3011                 lua_rawset(L, -3);
3012             }
3013             lua_setfield(L, -2, "params");
3014         } else {
3015             lua_pushnil(L);
3016         }
3017         break;
3018     case FK_anchor_classes:
3019         if (sf->anchor != NULL) {
3020             lua_newtable(L);
3021             handle_anchorclass(L, sf->anchor);
3022         } else {
3023             lua_pushnil(L);
3024         }
3025         break;
3026     case FK_kerns:
3027         if (sf->kerns != NULL) {
3028             lua_newtable(L);
3029             handle_kernclass(L, sf->kerns, NULL);
3030         } else {
3031             lua_pushnil(L);
3032         }
3033         break;
3034     case FK_vkerns:
3035         if (sf->vkerns != NULL) {
3036             lua_newtable(L);
3037             handle_kernclass(L, sf->vkerns, NULL);
3038         } else {
3039             lua_pushnil(L);
3040         }
3041         break;
3042     case FK_gsub:
3043         if (sf->gsub_lookups != NULL) {
3044             lua_newtable(L);
3045             handle_lookup(L, sf->gsub_lookups, sf);
3046         } else {
3047             lua_pushnil(L);
3048         }
3049         break;
3050     case FK_gpos:
3051         if (sf->gpos_lookups != NULL) {
3052             lua_newtable(L);
3053             handle_lookup(L, sf->gpos_lookups, sf);
3054         } else {
3055             lua_pushnil(L);
3056         }
3057         break;
3058     case FK_mm:
3059         if (sf->mm != NULL) {
3060             lua_newtable(L);
3061             handle_mmset(L, sf->mm);
3062         } else {
3063             lua_pushnil(L);
3064         }
3065         break;
3066     case FK_chosenname:
3067         lua_pushstring(L, sf->chosenname);
3068         break;
3069     case FK_macstyle:
3070         lua_pushnumber(L, sf->macstyle);
3071         break;
3072     case FK_fondname:
3073         lua_pushstring(L, sf->fondname);
3074         break;
3075     case FK_design_size:
3076         lua_pushnumber(L, sf->design_size);
3077         break;
3078     case FK_fontstyle_id:
3079         lua_pushnumber(L, sf->fontstyle_id);
3080         break;
3081     case FK_fontstyle_name:
3082         if (sf->fontstyle_name != NULL) {
3083             lua_newtable(L);
3084             handle_otfname(L, sf->fontstyle_name);
3085         } else {
3086             lua_pushnil(L);
3087         }
3088         break;
3089     case FK_design_range_bottom:
3090         lua_pushnumber(L, sf->design_range_bottom);
3091         break;
3092     case FK_design_range_top:
3093         lua_pushnumber(L, sf->design_range_top);
3094         break;
3095     case FK_strokewidth:
3096         lua_pushnumber(L, sf->strokewidth);
3097         break;
3098     case FK_mark_classes:
3099         if (sf->mark_class_cnt > 0) {
3100             lua_newtable(L);
3101             for (k = 0; k < sf->mark_class_cnt; k++) {
3102                 if (sf->mark_class_names[k] != NULL) {
3103                     lua_pushstring(L, sf->mark_class_names[k]);
3104                     lua_pushstring(L, sf->mark_classes[k]);
3105                     lua_rawset(L, -3);
3106                 }
3107             }
3108         } else {
3109             lua_pushnil(L);
3110         }
3111         break;
3112     case FK_creationtime:
3113         lua_pushnumber(L, sf->creationtime);
3114         break;
3115     case FK_modificationtime:
3116         lua_pushnumber(L, sf->modificationtime);
3117         break;
3118     case FK_os2_version:
3119         lua_pushnumber(L, sf->os2_version);
3120         break;
3121     case FK_sfd_version:
3122         lua_pushnumber(L, sf->sfd_version);
3123         break;
3124     case FK_math:
3125         if (sf->MATH != NULL) {
3126             lua_newtable(L);
3127             handle_MATH(L, sf->MATH);
3128         } else {
3129             lua_pushnil(L);
3130         }
3131         break;
3132     case FK_validation_state:
3133         if (sf->loadvalidation_state != 0) {
3134             int val, st;
3135             lua_newtable(L);
3136             val = 1;
3137             st = sf->loadvalidation_state;
3138             if (st & lvs_bad_ps_fontname) {
3139                 lua_pushliteral(L, "bad_ps_fontname");
3140                 lua_rawseti(L, -2, val++);
3141             }
3142             if (st & lvs_bad_glyph_table) {
3143                 lua_pushliteral(L, "bad_glyph_table");
3144                 lua_rawseti(L, -2, val++);
3145             }
3146             if (st & lvs_bad_cff_table) {
3147                 lua_pushliteral(L, "bad_cff_table");
3148                 lua_rawseti(L, -2, val++);
3149             }
3150             if (st & lvs_bad_metrics_table) {
3151                 lua_pushliteral(L, "bad_metrics_table");
3152                 lua_rawseti(L, -2, val++);
3153             }
3154             if (st & lvs_bad_cmap_table) {
3155                 lua_pushliteral(L, "bad_cmap_table");
3156                 lua_rawseti(L, -2, val++);
3157             }
3158             if (st & lvs_bad_bitmaps_table) {
3159                 lua_pushliteral(L, "bad_bitmaps_table");
3160                 lua_rawseti(L, -2, val++);
3161             }
3162             if (st & lvs_bad_gx_table) {
3163                 lua_pushliteral(L, "bad_gx_table");
3164                 lua_rawseti(L, -2, val++);
3165             }
3166             if (st & lvs_bad_ot_table) {
3167                 lua_pushliteral(L, "bad_ot_table");
3168                 lua_rawseti(L, -2, val++);
3169             }
3170             if (st & lvs_bad_os2_version) {
3171                 lua_pushliteral(L, "bad_os2_version");
3172                 lua_rawseti(L, -2, val++);
3173             }
3174             if (st & lvs_bad_sfnt_header) {
3175                 lua_pushliteral(L, "bad_sfnt_header");
3176                 lua_rawseti(L, -2, val++);
3177             }
3178         } else {
3179             lua_pushnil(L);
3180         }
3181         break;
3182     case FK_horiz_base:
3183         if (sf->horiz_base != NULL) {
3184             lua_newtable(L);
3185             handle_base(L, sf->horiz_base);
3186         } else {
3187             lua_pushnil(L);
3188         }
3189         break;
3190     case FK_vert_base:
3191         if (sf->vert_base != NULL) {
3192             lua_newtable(L);
3193             handle_base(L, sf->vert_base);
3194         } else {
3195             lua_pushnil(L);
3196         }
3197         break;
3198     case FK_extrema_bound:
3199         lua_pushnumber(L, sf->extrema_bound);
3200         break;
3201     default:                   /* can't actually happen, |luaL_checkoption| raises an error instead */
3202         lua_pushnil(L);
3203         break;
3204     }
3205     return 1;
3206 }
3207 
3208 
ff_info(lua_State * L)3209 static int ff_info(lua_State * L)
3210 {
3211     SplineFont *sf;
3212     FILE *l;
3213     int i;
3214     const char *fontname;
3215     int openflags = 1;
3216     fontname = luaL_checkstring(L, 1);
3217     if (!strlen(fontname)) {
3218         lua_pushnil(L);
3219         lua_pushfstring(L, "font loading failed: empty string given\n",
3220                         fontname);
3221         return 2;
3222     }
3223     /* test fontname for existance */
3224     if ((l = fopen(fontname, "r"))) {
3225         recorder_record_input(fontname);
3226         fclose(l);
3227     } else {
3228         lua_pushnil(L);
3229         lua_pushfstring(L, "font loading failed for %s (read error)\n",
3230                         fontname);
3231         return 2;
3232     }
3233 
3234     gww_error_count = 0;
3235     sf = ReadSplineFontInfo((char *) fontname, openflags);
3236     if (gww_error_count > 0)
3237         gwwv_errors_free();
3238 
3239     if (sf == NULL) {
3240         lua_pushnil(L);
3241         lua_pushfstring(L, "font loading failed for %s\n", fontname);
3242         return 2;
3243     } else {
3244         if (sf->next != NULL) {
3245             SplineFont *sf_next;
3246             i = 1;
3247             lua_newtable(L);
3248             while (sf) {
3249                 do_ff_info(L, sf);
3250                 lua_rawseti(L, -2, i);
3251                 i++;
3252                 sf_next = sf->next;
3253                 EncMapFree(sf->map);
3254                 SplineFontFree(sf);
3255                 sf = sf_next;
3256             }
3257         } else {
3258             do_ff_info(L, sf);
3259             EncMapFree(sf->map);
3260             SplineFontFree(sf);
3261         }
3262     }
3263     return 1;
3264 }
3265 
ff_do_cff(SplineFont * sf,char * filename,unsigned char ** buf,int * bufsiz)3266 static void ff_do_cff(SplineFont * sf, char *filename, unsigned char **buf,
3267                       int *bufsiz)
3268 {
3269     FILE *f;
3270     int32 *bsizes = NULL;
3271     int flags = ps_flag_nocffsugar + ps_flag_nohints;
3272     EncMap *map;
3273 
3274     map = EncMap1to1(sf->glyphcnt);
3275 
3276     if (WriteTTFFont
3277         (filename, sf, ff_cff, bsizes, bf_none, flags, map, ly_fore)) {
3278         /* success */
3279         f = fopen(filename, "rb");
3280         recorder_record_input(filename);
3281         readbinfile(f, buf, bufsiz);
3282         /*fprintf(stdout,"\n%s => CFF, size: %d\n", sf->filename, *bufsiz); */
3283         fclose(f);
3284         return;
3285     }
3286     /* errors */
3287     fprintf(stdout, "\n%s => CFF, failed\n", sf->filename);
3288 
3289 }
3290 
3291 /* exported for writecff.c */
3292 
ff_createcff(char * file,unsigned char ** buf,int * bufsiz)3293 int ff_createcff(char *file, unsigned char **buf, int *bufsiz)
3294 {
3295     SplineFont *sf;
3296     int k;
3297     char s[] = "tempfile.cff";
3298     int openflags = 1;
3299     int notdefpos = 0;
3300     sf = ReadSplineFont(file, openflags);
3301     if (sf) {
3302         /* this is not the best way. nicer to have no temp file at all */
3303         ff_do_cff(sf, s, buf, bufsiz);
3304         for (k = 0; k < sf->glyphcnt; k++) {
3305             if (sf->glyphs[k] && strcmp(sf->glyphs[k]->name, ".notdef") == 0) {
3306                 notdefpos = k;
3307                 break;
3308             }
3309         }
3310         remove(s);
3311         EncMapFree(sf->map);
3312         SplineFontFree(sf);
3313     }
3314     return notdefpos;
3315 }
3316 
ff_get_ttc_index(char * ffname,char * psname)3317 int ff_get_ttc_index(char *ffname, char *psname)
3318 {
3319     SplineFont *sf;
3320     int i = 0;
3321     int openflags = 1;
3322     int index = -1;
3323 
3324     sf = ReadSplineFontInfo((char *) ffname, openflags);
3325     if (sf == NULL) {
3326         perror("font loading failed unexpectedly\n");
3327         exit(EXIT_FAILURE);
3328     }
3329     while (sf != NULL) {
3330         if (strcmp(sf->fontname, psname) == 0) {
3331             index = i;
3332         }
3333         i++;
3334         sf = sf->next;
3335     }
3336     if (index>=0)
3337 	return (i-index-1);
3338     return -1;
3339 }
3340 
3341 static struct luaL_Reg fllib[] = {
3342     {"open", ff_open},
3343     {"info", ff_info},
3344     {"close", ff_close},
3345     {"fields", ff_fields},
3346     {"apply_afmfile", ff_apply_afmfile},
3347     {"apply_featurefile", ff_apply_featurefile},
3348     {"to_table", ff_make_table},
3349     {NULL, NULL}
3350 };
3351 
3352 static const struct luaL_Reg fflib_m[] = {
3353     {"__gc", ff_close},         /* doesnt work yet! */
3354     {"__index", ff_index},
3355     {NULL, NULL}                /* sentinel */
3356 };
3357 
3358 extern char *SaveTablesPref;
3359 extern char *coord_sep;
3360 
luaopen_ff(lua_State * L)3361 int luaopen_ff(lua_State * L)
3362 {
3363     InitSimpleStuff();
3364     setlocale(LC_ALL, "C");     /* undo whatever InitSimpleStuff has caused */
3365     coord_sep = ",";
3366     FF_SetUiInterface(&luaui_interface);
3367     default_encoding = FindOrMakeEncoding("ISO8859-1");
3368     SaveTablesPref = "VORG,JSTF,acnt,bsln,fdsc,fmtx,hsty,just,trak,Zapf,LINO";
3369     luaL_newmetatable(L, FONT_METATABLE);
3370     luaL_register(L, NULL, fflib_m);
3371 
3372     /* virtual subfont table */
3373     luaL_newmetatable(L, FONT_SUBFONT_METATABLE);
3374     lua_pushstring(L, "__index");
3375     lua_pushcfunction(L, ff_index);
3376     lua_rawset(L, -3);
3377     lua_pop(L, 1);
3378     /* virtual glyphs table */
3379     luaL_newmetatable(L, FONT_GLYPHS_METATABLE);
3380     lua_pushstring(L, "__index");
3381     lua_pushcfunction(L, ff_glyphs_index);
3382     lua_rawset(L, -3);
3383     lua_pop(L, 1);
3384     /* virtual glyph table */
3385     luaL_newmetatable(L, FONT_GLYPH_METATABLE);
3386     lua_pushstring(L, "__index");
3387     lua_pushcfunction(L, ff_glyph_index);
3388     lua_rawset(L, -3);
3389     lua_pop(L, 1);
3390 
3391 
3392     luaL_openlib(L, "fontloader", fllib, 0);
3393 
3394     return 1;
3395 }
3396