beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / font / luafont.w
blob6843cef5cd0cdbd9c60b05315e459884295fa492
1 % luafont.w
3 % Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
5 % This file is part of LuaTeX.
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.
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.
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/>.
20 @ @c
21 #include "ptexlib.h"
22 #include "lua/luatex-api.h"
24 #define noVERBOSE
26 /* todo: also keys */
28 const char *font_type_strings[] = {
29 "unknown", "virtual", "real", NULL
32 const char *font_format_strings[] = {
33 "unknown", "type1", "type3", "truetype", "opentype", NULL
36 const char *font_embedding_strings[] = {
37 "unknown", "no", "subset", "full", NULL
40 const char *ligature_type_strings[] = {
41 "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL
44 const char *MATH_param_names[] = {
45 "nil",
46 "ScriptPercentScaleDown",
47 "ScriptScriptPercentScaleDown",
48 "DelimitedSubFormulaMinHeight",
49 "DisplayOperatorMinHeight",
50 "MathLeading",
51 "AxisHeight",
52 "AccentBaseHeight",
53 "FlattenedAccentBaseHeight",
54 "SubscriptShiftDown",
55 "SubscriptTopMax",
56 "SubscriptBaselineDropMin",
57 "SuperscriptShiftUp",
58 "SuperscriptShiftUpCramped",
59 "SuperscriptBottomMin",
60 "SuperscriptBaselineDropMax",
61 "SubSuperscriptGapMin",
62 "SuperscriptBottomMaxWithSubscript",
63 "SpaceAfterScript",
64 "UpperLimitGapMin",
65 "UpperLimitBaselineRiseMin",
66 "LowerLimitGapMin",
67 "LowerLimitBaselineDropMin",
68 "StackTopShiftUp",
69 "StackTopDisplayStyleShiftUp",
70 "StackBottomShiftDown",
71 "StackBottomDisplayStyleShiftDown",
72 "StackGapMin",
73 "StackDisplayStyleGapMin",
74 "StretchStackTopShiftUp",
75 "StretchStackBottomShiftDown",
76 "StretchStackGapAboveMin",
77 "StretchStackGapBelowMin",
78 "FractionNumeratorShiftUp",
79 "FractionNumeratorDisplayStyleShiftUp",
80 "FractionDenominatorShiftDown",
81 "FractionDenominatorDisplayStyleShiftDown",
82 "FractionNumeratorGapMin",
83 "FractionNumeratorDisplayStyleGapMin",
84 "FractionRuleThickness",
85 "FractionDenominatorGapMin",
86 "FractionDenominatorDisplayStyleGapMin",
87 "SkewedFractionHorizontalGap",
88 "SkewedFractionVerticalGap",
89 "OverbarVerticalGap",
90 "OverbarRuleThickness",
91 "OverbarExtraAscender",
92 "UnderbarVerticalGap",
93 "UnderbarRuleThickness",
94 "UnderbarExtraDescender",
95 "RadicalVerticalGap",
96 "RadicalDisplayStyleVerticalGap",
97 "RadicalRuleThickness",
98 "RadicalExtraAscender",
99 "RadicalKernBeforeDegree",
100 "RadicalKernAfterDegree",
101 "RadicalDegreeBottomRaisePercent",
102 "MinConnectorOverlap",
103 "SubscriptShiftDownWithSuperscript",
104 "FractionDelimiterSize",
105 "FractionDelimiterDisplayStyleSize",
106 NULL,
109 /* here for now, may be useful elsewhere */
111 int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
113 int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) {
114 const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
115 int i;
116 for (i=0; lst[i]; i++)
117 if (strcmp(lst[i], name) == 0)
118 return i;
119 return -1;
122 #define dump_intfield(L,n,c) \
123 lua_push_string_by_name(L,n); \
124 lua_pushinteger(L, c); \
125 lua_rawset(L, -3); \
127 #define dump_stringfield(L,n,c) \
128 lua_push_string_by_name(L,n); \
129 lua_pushstring(L, c); \
130 lua_rawset(L, -3);
132 #define dump_booleanfield(L,n,c) \
133 lua_push_string_by_name(L,n); \
134 lua_pushboolean(L, c); \
135 lua_rawset(L, -3);
137 static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
139 int i;
140 for (i = 0; i < l; i++) {
141 lua_newtable(L);
142 if (id==top_left_kern) {
143 dump_intfield(L, height, co->top_left_math_kern_array[(2*i)]);
144 dump_intfield(L, kern, co->top_left_math_kern_array[(2*i)+1]);
145 } else if (id==top_right_kern) {
146 dump_intfield(L, height, co->top_right_math_kern_array[(2*i)]);
147 dump_intfield(L, kern, co->top_right_math_kern_array[(2*i)+1]);
148 } else if (id==bottom_right_kern) {
149 dump_intfield(L, height, co->bottom_right_math_kern_array[(2*i)]);
150 dump_intfield(L, kern, co->bottom_right_math_kern_array[(2*i)+1]);
151 } else if (id==bottom_left_kern) {
152 dump_intfield(L, height, co->bottom_left_math_kern_array[(2*i)]);
153 dump_intfield(L, kern, co->bottom_left_math_kern_array[(2*i)+1]);
155 lua_rawseti(L, -2, (i + 1));
159 static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
161 liginfo *l;
162 kerninfo *ki;
164 lua_createtable(L, 0, 10);
166 dump_intfield(L,width,get_charinfo_width(co));
167 dump_intfield(L,height,get_charinfo_height(co));
168 dump_intfield(L,depth,get_charinfo_depth(co));
170 if (get_charinfo_italic(co) != 0) {
171 dump_intfield(L,italic,get_charinfo_italic(co));
173 if (get_charinfo_vert_italic(co) != 0) {
174 dump_intfield(L,vert_italic,get_charinfo_vert_italic(co));
176 if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) {
177 dump_intfield(L,top_accent,get_charinfo_top_accent(co));
179 if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) {
180 dump_intfield(L,bot_accent,get_charinfo_bot_accent(co));
182 if (get_charinfo_ef(co) != 1000) {
183 dump_intfield(L,expansion_factor,get_charinfo_ef(co));
185 if (get_charinfo_lp(co) != 0) {
186 dump_intfield(L,left_protruding,get_charinfo_lp(co));
188 if (get_charinfo_rp(co) != 0) {
189 dump_intfield(L,right_protruding,get_charinfo_rp(co));
191 if (font_encodingbytes(f) == 2) {
192 dump_intfield(L,index,get_charinfo_index(co));
194 if (get_charinfo_name(co) != NULL) {
195 dump_stringfield(L,name,get_charinfo_name(co));
197 if (get_charinfo_tounicode(co) != NULL) {
198 dump_stringfield(L,tounicode,get_charinfo_tounicode(co));
200 if (get_charinfo_tag(co) == list_tag) {
201 dump_intfield(L,next,get_charinfo_remainder(co));
203 if (get_charinfo_used(co)) {
204 dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false));
206 if (get_charinfo_tag(co) == ext_tag) {
207 extinfo *h;
208 h = get_charinfo_hor_variants(co);
209 if (h != NULL) {
210 int i = 1;
211 lua_push_string_by_name(L,horiz_variants);
212 lua_newtable(L);
213 while (h != NULL) {
214 lua_createtable(L, 0, 5);
215 dump_intfield(L, glyph, h->glyph);
216 dump_intfield(L, extender, h->extender);
217 dump_intfield(L, start, h->start_overlap);
218 dump_intfield(L, end, h->end_overlap);
219 dump_intfield(L, advance, h->advance);
220 lua_rawseti(L, -2, i);
221 i++;
222 h = h->next;
224 lua_rawset(L, -3);
226 h = get_charinfo_vert_variants(co);
227 if (h != NULL) {
228 int i = 1;
229 lua_push_string_by_name(L,vert_variants);
230 lua_newtable(L);
231 while (h != NULL) {
232 lua_createtable(L, 0, 5);
233 dump_intfield(L, glyph, h->glyph);
234 dump_intfield(L, extender, h->extender);
235 dump_intfield(L, start, h->start_overlap);
236 dump_intfield(L, end, h->end_overlap);
237 dump_intfield(L, advance, h->advance);
238 lua_rawseti(L, -2, i);
239 i++;
240 h = h->next;
242 lua_rawset(L, -3);
245 ki = get_charinfo_kerns(co);
246 if (ki != NULL) {
247 int i;
248 lua_push_string_by_name(L,kerns);
249 lua_createtable(L, 10, 1);
250 for (i = 0; !kern_end(ki[i]); i++) {
251 if (kern_disabled(ki[i])) {
252 /* skip like in lookup */
253 } else {
254 lua_rawgeti(L, -1, kern_char(ki[i]));
255 if (lua_type(L,-1) == LUA_TNIL) {
256 lua_pop(L,1);
257 if (kern_char(ki[i]) == right_boundarychar) {
258 lua_push_string_by_name(L,right_boundary);
259 } else {
260 lua_pushinteger(L, kern_char(ki[i]));
262 lua_pushinteger(L, kern_kern(ki[i]));
263 lua_rawset(L, -3);
264 } else {
265 /* first one wins */
266 lua_pop(L,1);
270 lua_rawset(L, -3);
272 l = get_charinfo_ligatures(co);
273 if (l != NULL) {
274 int i;
275 lua_push_string_by_name(L,ligatures);
276 lua_createtable(L, 10, 1);
277 for (i = 0; !lig_end(l[i]); i++) {
278 if (lig_char(l[i]) == right_boundarychar) {
279 lua_push_string_by_name(L,right_boundary);
280 } else {
281 lua_pushinteger(L, lig_char(l[i]));
283 lua_createtable(L, 0, 2);
284 lua_push_string_by_name(L,type);
285 lua_pushinteger(L, lig_type(l[i]));
286 lua_rawset(L, -3);
287 lua_push_string_by_name(L,char);
288 lua_pushinteger(L, lig_replacement(l[i]));
289 lua_rawset(L, -3);
290 lua_rawset(L, -3);
292 lua_rawset(L, -3);
295 lua_push_string_by_name(L,mathkern);
296 lua_newtable(L);
298 int i, j;
299 i = get_charinfo_math_kerns(co, top_right_kern);
300 j = 0;
301 if (i > 0) {
302 j++;
303 lua_push_string_by_name(L,top_right);
304 lua_newtable(L);
305 dump_math_kerns(L, co, i, top_right_kern);
306 lua_rawset(L, -3);
308 i = get_charinfo_math_kerns(co, top_left_kern);
309 if (i > 0) {
310 j++;
311 lua_push_string_by_name(L,top_left);
312 lua_newtable(L);
313 dump_math_kerns(L, co, i, top_left_kern);
314 lua_rawset(L, -3);
316 i = get_charinfo_math_kerns(co, bottom_right_kern);
317 if (i > 0) {
318 j++;
319 lua_push_string_by_name(L,bottom_right);
320 lua_newtable(L);
321 dump_math_kerns(L, co, i, bottom_right_kern);
322 lua_rawset(L, -3);
324 i = get_charinfo_math_kerns(co, bottom_left_kern);
325 if (i > 0) {
326 j++;
327 lua_push_string_by_name(L,bottom_left);
328 lua_newtable(L);
329 dump_math_kerns(L, co, i, bottom_left_kern);
330 lua_rawset(L, -3);
332 if (j > 0)
333 lua_rawset(L, -3);
334 else
335 lua_pop(L, 2);
339 static void write_lua_parameters(lua_State * L, int f)
341 int k;
342 lua_push_string_by_name(L,parameters);
343 lua_newtable(L);
344 for (k = 1; k <= font_params(f); k++) {
345 switch (k) {
346 case slant_code:
347 dump_intfield(L,slant,font_param(f, k));
348 break;
349 case space_code:
350 dump_intfield(L,space,font_param(f, k));
351 break;
352 case space_stretch_code:
353 dump_intfield(L,space_stretch,font_param(f, k));
354 break;
355 case space_shrink_code:
356 dump_intfield(L,space_shrink,font_param(f, k));
357 break;
358 case x_height_code:
359 dump_intfield(L,x_height,font_param(f, k));
360 break;
361 case quad_code:
362 dump_intfield(L,quad,font_param(f, k));
363 break;
364 case extra_space_code:
365 dump_intfield(L,extra_space,font_param(f, k));
366 break;
367 default:
368 lua_pushinteger(L, font_param(f, k));
369 lua_rawseti(L, -2, k);
372 lua_rawset(L, -3);
375 @ @c
376 static void write_lua_math_parameters(lua_State * L, int f)
378 int k;
379 lua_push_string_by_name(L,MathConstants);
380 lua_newtable(L);
381 for (k = 1; k <= font_math_params(f); k++) {
382 lua_pushinteger(L, font_math_param(f, k));
383 if (k <= MATH_param_max) {
384 lua_setfield(L, -2, MATH_param_names[k]);
385 } else {
386 lua_rawseti(L, -2, k);
389 lua_rawset(L, -3);
392 int font_to_lua(lua_State * L, int f)
394 int k;
395 charinfo *co;
396 if (font_cache_id(f) > 0) {
397 /* fetch the table from the registry if it was
398 saved there by |font_from_lua()| */
399 lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f));
400 /* fontdimens can be changed from tex code */
401 write_lua_parameters(L, f);
402 return 1;
405 lua_newtable(L);
406 lua_push_string_by_name(L,name);
407 lua_pushstring(L, font_name(f));
408 lua_rawset(L, -3);
409 if (font_area(f) != NULL) {
410 dump_stringfield(L,area,font_area(f));
412 if (font_filename(f) != NULL) {
413 dump_stringfield(L,filename,font_filename(f));
415 if (font_fullname(f) != NULL) {
416 dump_stringfield(L,fullname,font_fullname(f));
418 if (font_psname(f) != NULL) {
419 dump_stringfield(L,psname,font_psname(f));
421 if (font_encodingname(f) != NULL) {
422 dump_stringfield(L,encodingname,font_encodingname(f));
425 dump_booleanfield(L,used,(font_used(f) ? true : false));
426 dump_stringfield(L,type,font_type_strings[font_type(f)]);
427 dump_stringfield(L,format,font_format_strings[font_format(f)]);
428 dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]);
430 dump_intfield(L,units_per_em,font_units_per_em(f));
431 dump_intfield(L,size,font_size(f));
432 dump_intfield(L,designsize,font_dsize(f));
433 dump_intfield(L,checksum,font_checksum(f));
434 dump_intfield(L,slant,font_slant(f));
435 dump_intfield(L,extend,font_extend(f));
436 dump_intfield(L,direction,font_natural_dir(f));
437 dump_intfield(L,encodingbytes,font_encodingbytes(f));
438 dump_booleanfield(L,oldmath,font_oldmath(f));
439 dump_intfield(L,tounicode,font_tounicode(f));
441 /* the next one is read only */
442 if (font_max_shrink(f) != 0) {
443 dump_intfield(L,shrink,font_max_shrink(f));
445 if (font_max_stretch(f) != 0) {
446 dump_intfield(L,stretch,font_max_stretch(f));
448 if (font_step(f) != 0) {
449 dump_intfield(L,step,font_step(f));
451 if (font_auto_expand(f) != 0) {
452 dump_booleanfield(L,auto_expand,font_auto_expand(f));
454 if (pdf_font_attr(f) != 0) {
455 char *s = makecstring(pdf_font_attr(f));
456 dump_stringfield(L,attributes,s);
457 free(s);
460 /* params */
461 write_lua_parameters(L, f);
462 write_lua_math_parameters(L, f);
464 /* chars */
465 lua_push_string_by_name(L,characters);
466 lua_createtable(L, font_tables[f]->charinfo_size, 0); /* all characters */
467 if (has_left_boundary(f)) {
468 co = get_charinfo(f, left_boundarychar);
469 lua_push_string_by_name(L,left_boundary);
470 font_char_to_lua(L, f, co);
471 lua_rawset(L, -3);
473 if (has_right_boundary(f)) {
474 co = get_charinfo(f, right_boundarychar);
475 lua_push_string_by_name(L,right_boundary);
476 font_char_to_lua(L, f, co);
477 lua_rawset(L, -3);
479 for (k = font_bc(f); k <= font_ec(f); k++) {
480 if (quick_char_exists(f, k)) {
481 lua_pushinteger(L, k);
482 co = get_charinfo(f, k);
483 font_char_to_lua(L, f, co);
484 lua_rawset(L, -3);
487 lua_rawset(L, -3);
489 if (font_cache_id(f) == 0) { /* renew */
490 int r;
491 lua_pushvalue(L, -1);
492 r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
493 set_font_cache_id(f, r);
495 return 1;
498 #define count_hash_items(L,name_index,n) \
499 n = 0; \
500 lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); \
501 lua_rawget(L, -2); \
502 if (lua_type(L, -1) == LUA_TTABLE) { \
503 lua_pushnil(L); \
504 while (lua_next(L, -2) != 0) { \
505 n++; \
506 lua_pop(L, 1); \
509 if (n) { \
510 /* keep table on stack */ \
511 } else{ \
512 lua_pop(L, 1); \
515 @ @c
516 #define streq(a,b) (strcmp(a,b)==0)
518 #define append_packet(k) { *(cp++) = (eight_bits) (k); }
520 #define do_store_four(l) { \
521 append_packet((l & 0xFF000000) >> 24); \
522 append_packet((l & 0x00FF0000) >> 16); \
523 append_packet((l & 0x0000FF00) >> 8); \
524 append_packet((l & 0x000000FF)); \
527 @ @c
528 static void append_float(eight_bits ** cpp, float a)
530 unsigned int i;
531 eight_bits *cp = *cpp;
532 union U {
533 float a;
534 eight_bits b[sizeof(float)];
535 } u;
536 u.a = a;
537 for (i = 0; i < sizeof(float); i++)
538 append_packet(u.b[i]);
539 *cpp = cp;
542 static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values)
544 int k, t;
545 const char *s;
546 int i = dflt;
547 lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
548 lua_rawget(L, -2);
549 t = lua_type(L,-1);
550 if (t == LUA_TNUMBER) {
551 i = (int) lua_tointeger(L, -1);
552 } else if (t == LUA_TSTRING) {
553 s = lua_tostring(L, -1);
554 k = 0;
555 while (values[k] != NULL) {
556 if (strcmp(values[k], s) == 0) {
557 i = k;
558 break;
560 k++;
563 lua_pop(L, 1);
564 return i;
567 static int n_boolean_field(lua_State * L, int name_index, int dflt)
569 int i = dflt;
570 lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
571 lua_rawget(L, -2);
572 if (lua_isboolean(L, -1)) {
573 i = lua_toboolean(L, -1);
575 lua_pop(L, 1);
576 return i;
579 static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
581 char *i;
582 lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
583 lua_rawget(L, -2);
584 if (lua_type(L,-1) == LUA_TSTRING) {
585 i = xstrdup(lua_tostring(L, -1));
586 } else if (dflt == NULL) {
587 i = NULL;
588 } else {
589 i = xstrdup(dflt);
591 lua_pop(L, 1);
592 return i;
595 static const char *n_string_field(lua_State * L, int name_index)
597 lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
598 lua_rawget(L, -2);
599 return lua_tostring(L,-1);
602 static int n_some_field(lua_State * L, int name_index)
604 lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
605 lua_rawget(L, -2);
606 return lua_type(L,-1);
609 /*static void init_font_string_pointers(lua_State * L){}*/
611 static int count_char_packet_bytes(lua_State * L)
613 register int i;
614 register int l = 0;
615 int ff = 0;
616 for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
617 lua_rawgeti(L, -1, i);
618 if (lua_istable(L, -1)) {
619 lua_rawgeti(L, -1, 1);
620 if (lua_type(L,-1) == LUA_TSTRING) {
621 const char *s = lua_tostring(L, -1);
622 if (lua_key_eq(s, font)) {
623 l += 5;
624 ff = 1;
625 } else if (lua_key_eq(s, char)) {
626 if (ff == 0) {
627 l += 5;
629 l += 5;
630 ff = 1;
631 } else if (lua_key_eq(s, slot)) {
632 l += 10;
633 ff = 1;
634 } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
636 } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
637 l++;
638 } else if (lua_key_eq(s, rule)) {
639 l += 9;
640 } else if (lua_key_eq(s, right) || lua_key_eq(s, node)
641 || lua_key_eq(s, down) || lua_key_eq(s, image)) {
642 l += 5;
643 } else if (lua_key_eq(s, scale)) {
644 l += sizeof(float) + 1;
645 } else if (lua_key_eq(s, special) || lua_key_eq(s, lua)) {
646 size_t len;
647 lua_rawgeti(L, -2, 2);
648 if (lua_type(L,-1) == LUA_TSTRING) {
649 (void) lua_tolstring(L, -1, &len);
650 lua_pop(L, 1);
651 if (len > 0) {
652 l = (int) (l + 5 + (int) len);
654 } else {
655 lua_pop(L, 1);
656 normal_error("vf command","invalid packet special");
657 /* fprintf(stdout, "invalid packet special!\n"); */
659 } else {
660 normal_error("vf command","unknown packet command");
661 /* fprintf(stdout, "unknown packet command %s!\n", s); */
663 } else {
664 normal_error("vf command","no packet command");
665 /* fprintf(stdout, "no packet command!\n"); */
667 lua_pop(L, 1); /* command name */
669 lua_pop(L, 1); /* item */
671 return l;
674 static scaled sp_to_dvi(halfword sp, halfword atsize)
676 double result, mult;
677 mult = (double) (atsize / 65536.0);
678 result = (double) (sp * 16.0);
679 return floor(result / mult);
682 @ @c
683 static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, internal_font_number f, int atsize)
685 int i, n, m;
686 size_t l;
687 int cmd;
688 const char *s;
689 eight_bits *cpackets, *cp;
690 int ff = 0;
691 int max_f = 0;
692 int pc = count_char_packet_bytes(L);
693 if (pc <= 0)
694 return;
695 while (l_fonts[(max_f + 1)] != 0)
696 max_f++;
697 cp = cpackets = xmalloc((unsigned) (pc + 1));
698 for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
699 lua_rawgeti(L, -1, i);
700 if (lua_istable(L, -1)) {
701 /* fetch the command code */
702 lua_rawgeti(L, -1, 1);
703 if (lua_type(L,-1) == LUA_TSTRING) {
704 s = lua_tostring(L, -1);
705 cmd = 0;
706 if (lua_key_eq(s, font)) {
707 cmd = packet_font_code;
708 } else if (lua_key_eq(s, char)) {
709 cmd = packet_char_code;
710 if (ff == 0) {
711 append_packet(packet_font_code);
712 ff = l_fonts[1];
713 do_store_four(ff);
715 } else if (lua_key_eq(s, slot)) {
716 cmd = packet_nop_code;
717 lua_rawgeti(L, -2, 2);
718 n = (int) luaL_checkinteger(L, -1);
719 if (n ==0) {
720 ff = f;
721 } else {
722 ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
724 lua_rawgeti(L, -3, 3);
725 n = (int) luaL_checkinteger(L, -1);
726 lua_pop(L, 2);
727 append_packet(packet_font_code);
728 do_store_four(ff);
729 append_packet(packet_char_code);
730 do_store_four(n);
731 } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
732 cmd = packet_nop_code;
733 } else if (lua_key_eq(s, node)) {
734 cmd = packet_node_code;
735 } else if (lua_key_eq(s, push)) {
736 cmd = packet_push_code;
737 } else if (lua_key_eq(s, pop)) {
738 cmd = packet_pop_code;
739 } else if (lua_key_eq(s, rule)) {
740 cmd = packet_rule_code;
741 } else if (lua_key_eq(s, right)) {
742 cmd = packet_right_code;
743 } else if (lua_key_eq(s, down)) {
744 cmd = packet_down_code;
745 } else if (lua_key_eq(s, special)) {
746 cmd = packet_special_code;
747 } else if (lua_key_eq(s, image)) {
748 cmd = packet_image_code;
749 } else if (lua_key_eq(s, scale)) {
750 cmd = packet_scale_code;
751 } else if (lua_key_eq(s, lua)) {
752 cmd = packet_lua_code;
754 switch (cmd) {
755 case packet_push_code:
756 case packet_pop_code:
757 append_packet(cmd);
758 break;
759 case packet_font_code:
760 append_packet(cmd);
761 lua_rawgeti(L, -2, 2);
762 n = (int) luaL_checkinteger(L, -1);
763 if (n == 0) {
764 ff = n;
765 } else {
766 ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
768 do_store_four(ff);
769 lua_pop(L, 1);
770 break;
771 case packet_node_code:
772 append_packet(cmd);
773 lua_rawgeti(L, -2, 2);
774 n = copy_node_list(nodelist_from_lua(L));
775 do_store_four(n);
776 lua_pop(L, 1);
777 break;
778 case packet_char_code:
779 append_packet(cmd);
780 lua_rawgeti(L, -2, 2);
781 n = (int) luaL_checkinteger(L, -1);
782 do_store_four(n);
783 lua_pop(L, 1);
784 break;
785 case packet_right_code:
786 case packet_down_code:
787 append_packet(cmd);
788 lua_rawgeti(L, -2, 2);
789 n = (int) luaL_checkinteger(L, -1);
790 do_store_four(sp_to_dvi(n, atsize));
791 lua_pop(L, 1);
792 break;
793 case packet_rule_code:
794 append_packet(cmd);
795 lua_rawgeti(L, -2, 2);
796 n = (int) luaL_checkinteger(L, -1);
797 do_store_four(sp_to_dvi(n, atsize));
798 lua_rawgeti(L, -3, 3);
799 n = (int) luaL_checkinteger(L, -1);
800 do_store_four(sp_to_dvi(n, atsize));
801 lua_pop(L, 2);
802 break;
803 case packet_special_code:
804 case packet_lua_code:
805 append_packet(cmd);
806 lua_rawgeti(L, -2, 2);
807 s = luaL_checklstring(L, -1, &l);
808 if (l > 0) {
809 do_store_four(l);
810 m = (int) l;
811 while (m > 0) {
812 n = *s++;
813 m--;
814 append_packet(n);
817 lua_pop(L, 1);
818 break;
819 case packet_image_code:
820 append_packet(cmd);
821 lua_rawgeti(L, -2, 2); /* img/imgtable? ... */
822 if (lua_istable(L, -1)) { /* imgtable ... */
823 lua_getglobal(L, "img"); /* imglib imgtable ... */
824 lua_pushstring(L, "new"); /* `new' imglib imgtable ... */
825 lua_gettable(L, -2); /* f imglib imgtable ... */
826 lua_insert(L, -3); /* imglib imgtable f ... */
827 lua_pop(L, 1); /* imgtable f ... */
828 lua_call(L, 1, 1);
829 } /* img ... */
830 luaL_checkudata(L, -1, TYPE_IMG); /* img ... --- just typecheck */
831 n = luaL_ref(L, LUA_REGISTRYINDEX); /* ... */
832 do_store_four(n);
833 break;
834 case packet_nop_code:
835 break;
836 case packet_scale_code:
837 append_packet(cmd);
838 lua_rawgeti(L, -2, 2);
839 append_float(&cp, (float) luaL_checknumber(L, -1));
840 lua_pop(L, 1);
841 break;
842 default:
843 normal_error("vf command","invalid packet code");
844 /* fprintf(stdout, "Unknown char packet code %s\n", s); */
847 lua_pop(L, 1); /* command code */
848 } else {
849 normal_error("vf command","commands has to be a tbale");
850 /* fprintf(stdout, "Found a `commands' item that is not a table\n"); */
852 lua_pop(L, 1); /* command table */
854 append_packet(packet_end_code);
855 set_charinfo_packets(co, cpackets);
856 return;
859 @ @c
860 static void read_lua_cidinfo(lua_State * L, int f)
862 int i;
863 char *s;
864 /*lua_getfield(L, -1, "cidinfo");*/
865 lua_key_rawgeti(cidinfo);
866 if (lua_istable(L, -1)) {
867 i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
868 set_font_cidversion(f, i);
869 i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
870 set_font_cidsupplement(f, i);
871 s = n_string_field_copy(L, lua_key_index(registry), "Adobe"); /* Adobe-Identity-0 */
872 set_font_cidregistry(f, s);
873 s = n_string_field_copy(L, lua_key_index(ordering), "Identity");
874 set_font_cidordering(f, s);
876 lua_pop(L, 1);
880 @ @c
881 static void read_lua_parameters(lua_State * L, int f)
883 int i, n, t;
884 const char *s;
885 /*lua_getfield(L, -1, "parameters");*/
886 lua_key_rawgeti(parameters);
887 if (lua_istable(L, -1)) {
888 /* the number of parameters is the max(IntegerKeys(L)),7) */
889 n = 7;
890 lua_pushnil(L); /* first key */
891 while (lua_next(L, -2) != 0) {
892 if (lua_type(L, -2) == LUA_TNUMBER) {
893 i = (int) lua_tointeger(L, -2);
894 if (i > n)
895 n = i;
897 lua_pop(L, 1); /* pop value */
899 if (n > 7)
900 set_font_params(f, n);
901 /* sometimes it is handy to have all integer keys */
902 for (i = 1; i <= 7; i++) {
903 lua_rawgeti(L, -1, i);
904 if (lua_type(L, -1) == LUA_TNUMBER) {
905 n = lua_roundnumber(L, -1); /* round ? */
906 set_font_param(f, i, n);
908 lua_pop(L, 1);
910 lua_pushnil(L); /* first key */
911 while (lua_next(L, -2) != 0) {
912 t = lua_type(L,-2);
913 if (t == LUA_TNUMBER) {
914 i = (int) lua_tointeger(L, -2);
915 if (i >= 8) {
916 if (lua_type(L,-1) == LUA_TNUMBER) {
917 n = lua_roundnumber(L, -1);
918 } else {
919 n = 0;
921 set_font_param(f, i, n);
923 } else if (t == LUA_TSTRING) {
924 s = lua_tostring(L, -2);
925 if (lua_type(L,-1) == LUA_TNUMBER) {
926 n = lua_roundnumber(L, -1);
927 } else {
928 n = 0;
930 if (lua_key_eq(s, slant)) {
931 set_font_param(f, slant_code, n);
932 } else if (lua_key_eq(s, space)) {
933 set_font_param(f, space_code, n);
934 } else if (lua_key_eq(s, space_stretch)) {
935 set_font_param(f, space_stretch_code, n);
936 } else if (lua_key_eq(s, space_shrink)) {
937 set_font_param(f, space_shrink_code, n);
938 } else if (lua_key_eq(s, x_height)) {
939 set_font_param(f, x_height_code, n);
940 } else if (lua_key_eq(s, quad)) {
941 set_font_param(f, quad_code, n);
942 } else if (lua_key_eq(s, extra_space)) {
943 set_font_param(f, extra_space_code, n);
946 lua_pop(L, 1);
949 lua_pop(L, 1);
953 @ @c
954 static void read_lua_math_parameters(lua_State * L, int f)
956 int i = 0, n = 0, t;
957 /*lua_getfield(L, -1, "MathConstants");*/
958 lua_key_rawgeti(MathConstants);
959 if (lua_istable(L, -1)) {
960 lua_pushnil(L);
961 while (lua_next(L, -2) != 0) {
962 t = lua_type(L,-2);
963 if (t == LUA_TNUMBER) {
964 i = (int) lua_tointeger(L, -2);
965 } else if (t == LUA_TSTRING) {
966 i = ff_checkoption(L, -2, NULL, MATH_param_names);
968 n = (int) lua_tointeger(L, -1);
969 if (i > 0) {
970 set_font_math_param(f, i, n);
972 lua_pop(L, 1); /* pop value */
974 set_font_oldmath(f,false);
975 } else {
976 set_font_oldmath(f,true);
978 lua_pop(L, 1);
981 @ @c
982 #define MIN_INF -0x7FFFFFFF
984 static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
986 int l, k;
987 scaled ht, krn;
988 lua_rawgeti(L, LUA_REGISTRYINDEX, index);
989 lua_rawget(L, -2);
990 if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
991 for (l = 0; l < k; l++) {
992 lua_rawgeti(L, -1, (l + 1));
993 if (lua_istable(L, -1)) {
994 ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
995 krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
996 if (krn > MIN_INF && ht > MIN_INF)
997 add_charinfo_math_kern(co, id, ht, krn);
999 lua_pop(L, 1);
1002 lua_pop(L, 1);
1005 @ @c
1006 static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math)
1008 int k, r, t, lt, u, n;
1009 charinfo *co;
1010 kerninfo *ckerns;
1011 liginfo *cligs;
1012 scaled j;
1013 const char *s;
1014 int nl = 0; /* number of ligature table items */
1015 int nk = 0; /* number of kern table items */
1016 int ctr = 0;
1017 int atsize = font_size(f);
1018 if (lua_istable(L, -1)) {
1019 co = get_charinfo(f, i);
1020 set_charinfo_tag(co, 0);
1021 j = lua_numeric_field_by_index(L, lua_key_index(width), 0);
1022 set_charinfo_width(co, j);
1023 j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
1024 set_charinfo_height(co, j);
1025 j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
1026 set_charinfo_depth(co, j);
1027 j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
1028 set_charinfo_italic(co, j);
1029 j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0);
1030 set_charinfo_vert_italic(co, j);
1031 j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
1032 set_charinfo_index(co, j);
1033 j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000);
1034 set_charinfo_ef(co, j);
1035 j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
1036 set_charinfo_lp(co, j);
1037 j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
1038 set_charinfo_rp(co, j);
1039 k = n_boolean_field(L, lua_key_index(used), 0);
1040 set_charinfo_used(co, k);
1041 s = n_string_field(L, lua_key_index(name));
1042 if (s != NULL)
1043 set_charinfo_name(co, xstrdup(s));
1044 else
1045 set_charinfo_name(co, NULL);
1046 /* n_string_field leaves a value on stack*/
1047 lua_pop(L,1);
1048 u = n_some_field(L,lua_key_index(tounicode));
1049 if (u == LUA_TNUMBER) {
1050 u = lua_tointeger(L,-1);
1051 if (u < 0) {
1052 set_charinfo_tounicode(co, NULL);
1053 } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
1054 char *s = malloc(5);
1055 sprintf(s,"%04X",(unsigned int) u);
1056 set_charinfo_tounicode(co,s);
1057 } else {
1058 char *s = malloc(9);
1059 u = u - 0x10000;
1060 sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
1061 set_charinfo_tounicode(co,s);
1063 } else if (u == LUA_TTABLE) {
1064 n = lua_rawlen(L,-1);
1065 u = 0;
1066 for (k = 1; k <= n; k++) {
1067 lua_rawgeti(L, -1, k);
1068 if (lua_type(L,-1) == LUA_TNUMBER) {
1069 u = lua_tointeger(L,-1);
1070 } else {
1071 lua_pop(L, 1);
1072 break;
1074 if (u < 0) {
1075 u = -1;
1076 lua_pop(L, 1);
1077 break;
1078 } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
1079 u = u + 4;
1080 } else {
1081 u = u + 8;
1083 lua_pop(L, 1);
1085 if (u>0) {
1086 char *s = malloc(u+1);
1087 char *t = s ;
1088 for (k = 1; k <= n; k++) {
1089 lua_rawgeti(L, -1, k);
1090 u = lua_tointeger(L,-1);
1091 if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
1092 sprintf(t,"%04X",(unsigned int) u);
1093 t += 4;
1094 } else {
1095 u = u - 0x10000;
1096 sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
1097 t += 8;
1099 lua_pop(L, 1);
1101 set_charinfo_tounicode(co,s);
1102 } else {
1103 set_charinfo_tounicode(co, NULL);
1105 } else if (u == LUA_TSTRING) {
1106 s = lua_tostring(L,-1);
1107 set_charinfo_tounicode(co, xstrdup(s));
1108 } else {
1109 set_charinfo_tounicode(co, NULL);
1111 /* ... leaves a value on stack*/
1112 lua_pop(L,1);
1114 if (has_math) {
1115 j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
1116 set_charinfo_top_accent(co, j);
1117 j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
1118 set_charinfo_bot_accent(co, j);
1119 k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
1120 if (k >= 0) {
1121 set_charinfo_tag(co, list_tag);
1122 set_charinfo_remainder(co, k);
1125 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(extensible));
1126 lua_rawget(L, -2);
1127 if (lua_istable(L, -1)) {
1128 int top, bot, mid, rep;
1129 top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
1130 bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
1131 mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
1132 rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0);
1133 if (top != 0 || bot != 0 || mid != 0 || rep != 0) {
1134 set_charinfo_tag(co, ext_tag);
1135 set_charinfo_extensible(co, top, bot, mid, rep);
1136 } else {
1137 formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field",
1138 font_name(f), (int) i);
1141 lua_pop(L, 1);
1143 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(horiz_variants));
1144 lua_rawget(L, -2);
1145 if (lua_istable(L, -1)) {
1146 int glyph, startconnect, endconnect, advance, extender;
1147 extinfo *h;
1148 set_charinfo_tag(co, ext_tag);
1149 set_charinfo_hor_variants(co, NULL);
1150 for (k = 1;; k++) {
1151 lua_rawgeti(L, -1, k);
1152 if (lua_istable(L, -1)) {
1153 glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
1154 extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
1155 startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
1156 endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
1157 advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
1158 h = new_variant(glyph, startconnect, endconnect, advance, extender);
1159 add_charinfo_hor_variant(co, h);
1160 lua_pop(L, 1);
1161 } else {
1162 lua_pop(L, 1);
1163 break;
1167 lua_pop(L, 1);
1169 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(vert_variants));
1170 lua_rawget(L, -2);
1171 if (lua_istable(L, -1)) {
1172 int glyph, startconnect, endconnect, advance, extender;
1173 extinfo *h;
1174 set_charinfo_tag(co, ext_tag);
1175 set_charinfo_vert_variants(co, NULL);
1176 for (k = 1;; k++) {
1177 lua_rawgeti(L, -1, k);
1178 if (lua_istable(L, -1)) {
1179 glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
1180 extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
1181 startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
1182 endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
1183 advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
1184 h = new_variant(glyph, startconnect, endconnect, advance, extender);
1185 add_charinfo_vert_variant(co, h);
1186 lua_pop(L, 1);
1187 } else {
1188 lua_pop(L, 1);
1189 break;
1193 lua_pop(L, 1);
1196 Here is a complete example:
1198 |mathkern = {|
1199 | bottom_left = { { height = 420, kern = 80 }, { height = 520, kern = 4 } },|
1200 | bottom_right = { { height = 0, kern = 48 } },|
1201 | top_left = { { height = 620, kern = 0 }, { height = 720, kern = -80 } },|
1202 | top_right = { { height = 676, kern = 115 }, { height = 776, kern = 45 } },|
1207 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(mathkern));
1208 lua_rawget(L, -2);
1209 if (lua_istable(L, -1)) {
1210 store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
1211 store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
1212 store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
1213 store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
1215 lua_pop(L, 1);
1217 /* end of |has_math| */
1218 count_hash_items(L, lua_key_index(kerns), nk);
1219 if (nk > 0) {
1220 /* kerns table still on stack */
1221 ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
1222 ctr = 0;
1223 lua_pushnil(L); /* traverse hash */
1224 while (lua_next(L, -2) != 0) {
1225 k = non_boundarychar;
1226 lt = lua_type(L,-2);
1227 if (lt == LUA_TNUMBER) {
1228 k = (int) lua_tointeger(L, -2); /* adjacent char */
1229 if (k < 0)
1230 k = non_boundarychar;
1231 } else if (lt == LUA_TSTRING) {
1232 s = lua_tostring(L, -2);
1233 if (lua_key_eq(s, right_boundary)) {
1234 k = right_boundarychar;
1235 if (!has_right_boundary(f))
1236 set_right_boundary(f, get_charinfo(f, right_boundarychar));
1239 j = lua_roundnumber(L, -1); /* movement */
1240 if (k != non_boundarychar) {
1241 set_kern_item(ckerns[ctr], k, j);
1242 ctr++;
1243 } else {
1244 formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kern field",
1245 font_name(f), (int) i);
1247 lua_pop(L, 1);
1249 /* guard against empty tables */
1250 if (ctr > 0) {
1251 set_kern_item(ckerns[ctr], end_kern, 0);
1252 set_charinfo_kerns(co, ckerns);
1253 } else {
1254 formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field",
1255 font_name(f), (int) i);
1257 lua_pop(L, 1);
1260 /* packet commands */
1261 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(commands));
1262 lua_rawget(L, -2);
1263 if (lua_istable(L, -1)) {
1264 lua_pushnil(L); /* first key */
1265 if (lua_next(L, -2) != 0) {
1266 lua_pop(L, 2);
1267 read_char_packets(L, (int *) l_fonts, co, f, atsize);
1270 lua_pop(L, 1);
1272 /* ligatures */
1273 count_hash_items(L, lua_key_index(ligatures),nl);
1274 if (nl > 0) {
1275 /* ligatures table still on stack */
1276 cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
1277 ctr = 0;
1278 lua_pushnil(L); /* traverse hash */
1279 while (lua_next(L, -2) != 0) {
1280 k = non_boundarychar;
1281 lt = lua_type(L,-2);
1282 if (lt == LUA_TNUMBER) {
1283 k = (int) lua_tointeger(L, -2); /* adjacent char */
1284 if (k < 0) {
1285 k = non_boundarychar;
1287 } else if (lt == LUA_TSTRING) {
1288 s = lua_tostring(L, -2);
1289 if (lua_key_eq(s, right_boundary)) {
1290 k = right_boundarychar;
1291 if (!has_right_boundary(f))
1292 set_right_boundary(f, get_charinfo(f, right_boundarychar));
1295 r = -1;
1296 if (lua_istable(L, -1)) {
1297 r = lua_numeric_field_by_index(L, lua_key_index(char), -1); /* ligature */
1299 if (r != -1 && k != non_boundarychar) {
1300 t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
1301 set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r);
1302 ctr++;
1303 } else {
1304 formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligature field",
1305 font_name(f), (int) i);
1307 lua_pop(L, 1); /* iterator value */
1309 /* guard against empty tables */
1310 if (ctr > 0) {
1311 set_ligature_item(cligs[ctr], 0, end_ligature, 0);
1312 set_charinfo_ligatures(co, cligs);
1313 } else {
1314 formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligatures field",
1315 font_name(f), (int) i);
1317 lua_pop(L, 1); /* ligatures table */
1322 @ The caller has to fix the state of the lua stack when there is an error!
1325 int font_from_lua(lua_State * L, int f)
1327 int i, n, r, t, lt;
1328 int s_top; /* lua stack top */
1329 int bc; /* first char index */
1330 int ec; /* last char index */
1331 char *s;
1332 const char *ss;
1333 int *l_fonts = NULL;
1334 int save_ref ;
1335 boolean no_math = false;
1337 /* will we save a cache of the luat table? */
1339 save_ref = 1; /* we start with ss = "yes" */
1340 ss = NULL;
1341 ss = n_string_field(L, lua_key_index(cache));
1342 if (lua_key_eq(ss, no))
1343 save_ref = -1;
1344 else if (lua_key_eq(ss, renew))
1345 save_ref = 0;
1346 /* n_string_field leaves a value on stack*/
1347 lua_pop(L,1);
1349 /* the table is at stack index -1 */
1351 s = n_string_field_copy(L,lua_key_index(area), "");
1352 set_font_area(f, s);
1353 s = n_string_field_copy(L, lua_key_index(filename), NULL);
1354 set_font_filename(f, s);
1355 s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
1356 set_font_encodingname(f, s);
1358 s = n_string_field_copy(L, lua_key_index(name), NULL);
1359 set_font_name(f, s);
1360 s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
1361 set_font_fullname(f, s);
1363 if (s == NULL) {
1364 formatted_error("font","lua-loaded font '%d' has no name!", f);
1365 return false;
1367 s = n_string_field_copy(L, lua_key_index(psname), NULL);
1368 set_font_psname(f, s);
1370 i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
1371 set_font_units_per_em(f, i);
1372 i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
1373 set_font_dsize(f, i);
1374 i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
1375 set_font_size(f, i);
1376 set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
1377 i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
1378 set_font_natural_dir(f, i);
1379 i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
1380 set_font_encodingbytes(f, (char) i);
1381 i = n_boolean_field(L,lua_key_index(oldmath), 0);
1382 set_font_oldmath(f, i);
1383 i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
1384 set_font_tounicode(f, (char) i);
1386 i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000);
1387 if (i < FONT_EXTEND_MIN)
1388 i = FONT_EXTEND_MIN;
1389 if (i > FONT_EXTEND_MAX)
1390 i = FONT_EXTEND_MAX;
1391 set_font_extend(f, i);
1392 i = lua_numeric_field_by_index(L,lua_key_index(slant), 0);
1393 if (i < FONT_SLANT_MIN)
1394 i = FONT_SLANT_MIN;
1395 if (i > FONT_SLANT_MAX)
1396 i = FONT_SLANT_MAX;
1397 set_font_slant(f, i);
1399 i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), int_par(default_hyphen_char_code));
1400 set_hyphen_char(f, i);
1401 i = lua_numeric_field_by_index(L,lua_key_index(skewchar), int_par(default_skew_char_code));
1402 set_skew_char(f, i);
1403 i = n_boolean_field(L, lua_key_index(used), 0);
1404 set_font_used(f, (char) i);
1406 s = n_string_field_copy(L, lua_key_index(attributes), NULL);
1407 if (s != NULL && strlen(s) > 0) {
1408 i = maketexstring(s);
1409 set_pdf_font_attr(f, i);
1411 free(s);
1413 i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
1414 set_font_type(f, i);
1415 i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
1416 set_font_format(f, i);
1417 i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings);
1418 set_font_embedding(f, i);
1419 if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) {
1420 set_font_encodingbytes(f, 2);
1423 /* now fetch the base fonts, if needed */
1424 count_hash_items(L, lua_key_index(fonts), n);
1425 if (n > 0) {
1426 /* font table still on stack */
1427 l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
1428 memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
1429 for (i = 1; i <= n; i++) {
1430 lua_rawgeti(L, -1, i);
1431 if (lua_istable(L, -1)) {
1432 lua_key_rawgeti(id);
1433 if (lua_isnumber(L, -1)) {
1434 l_fonts[i] = (int) lua_tointeger(L, -1);
1435 if (l_fonts[i] == 0) {
1436 l_fonts[i] = (int) f;
1438 lua_pop(L, 2); /* pop id and entry */
1439 continue;
1441 lua_pop(L, 1); /* pop id */
1443 ss = NULL;
1444 if (lua_istable(L, -1)) {
1445 ss = n_string_field(L, lua_key_index(name));
1446 /* string is anchored */
1447 lua_pop(L,1);
1449 if (ss != NULL) {
1450 t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
1451 /* TODO: the stack is messed up, otherwise this explicit resizing would not be needed */
1452 s_top = lua_gettop(L);
1453 if (strcmp(font_name(f), ss) == 0)
1454 l_fonts[i] = f;
1455 else
1456 l_fonts[i] = find_font_id(ss, t);
1457 lua_settop(L, s_top);
1458 } else {
1459 formatted_error("font","invalid local font in lua-loaded font '%s'", font_name(f));
1461 lua_pop(L, 1); /* pop list entry */
1463 lua_pop(L, 1); /* pop font table */
1464 } else if (font_type(f) == virtual_font_type) {
1465 formatted_error("font","invalid local fonts in lua-loaded font '%s'", font_name(f));
1466 } else {
1467 l_fonts = xmalloc(3 * sizeof(int));
1468 l_fonts[0] = 0;
1469 l_fonts[1] = f;
1470 l_fonts[2] = 0;
1473 /* parameters */
1474 no_math = n_boolean_field(L, lua_key_index(nomath), 0);
1475 read_lua_parameters(L, f);
1476 if (!no_math) {
1477 read_lua_math_parameters(L, f);
1478 if (n_boolean_field(L, lua_key_index(oldmath), 0)) {
1479 set_font_oldmath(f,true);
1482 } else {
1483 set_font_oldmath(f,true);
1485 read_lua_cidinfo(L, f);
1487 /* characters */
1488 /*lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(characters));lua_rawget(L, -2);*/
1489 lua_key_rawgeti(characters);
1490 /*lua_getfield(L, -1, "characters");*/
1491 if (lua_istable(L, -1)) {
1492 /* find the array size values */
1493 int num = 0; /* number of charinfo's to add */
1494 ec = 0;
1495 bc = -1;
1496 lua_pushnil(L); /* first key */
1497 while (lua_next(L, -2) != 0) {
1498 if (lua_isnumber(L, -2)) {
1499 i = (int) lua_tointeger(L, -2);
1500 if (i >= 0) {
1501 if (lua_istable(L, -1)) {
1502 num++;
1503 if (i > ec)
1504 ec = i;
1505 if (bc < 0)
1506 bc = i;
1507 if (bc >= 0 && i < bc)
1508 bc = i;
1512 lua_pop(L, 1);
1514 if (bc != -1) {
1515 font_malloc_charinfo(f, num);
1516 set_font_bc(f, bc);
1517 set_font_ec(f, ec);
1518 lua_pushnil(L); /* first key */
1519 while (lua_next(L, -2) != 0) {
1520 lt = lua_type(L,-2);
1521 if (lt == LUA_TNUMBER) {
1522 i = (int) lua_tointeger(L, -2);
1523 if (i >= 0) {
1524 font_char_from_lua(L, f, i, l_fonts, !no_math);
1526 } else if (lt == LUA_TSTRING) {
1527 const char *ss1 = lua_tostring(L, -2);
1528 if (lua_key_eq(ss1, left_boundary)) {
1529 font_char_from_lua(L, f, left_boundarychar, l_fonts,
1530 !no_math);
1531 } else if (lua_key_eq(ss1, right_boundary)) {
1532 font_char_from_lua(L, f, right_boundarychar, l_fonts,
1533 !no_math);
1536 lua_pop(L, 1);
1538 lua_pop(L, 1);
1541 Handle font expansion last: the |copy_font| routine is called eventually,
1542 and that needs to know |bc| and |ec|.
1545 if (font_type(f) != virtual_font_type) {
1546 int fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0);
1547 if (fstep < 0)
1548 fstep = 0;
1549 if (fstep > 100)
1550 fstep = 100;
1551 if (fstep != 0) {
1552 int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
1553 int fstretch =lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
1554 int fexpand = n_boolean_field(L, lua_key_index(auto_expand), 0);
1555 if (fshrink < 0)
1556 fshrink = 0;
1557 if (fshrink > 500)
1558 fshrink = 500;
1559 fshrink -= (fshrink % fstep);
1560 if (fshrink < 0)
1561 fshrink = 0;
1562 if (fstretch < 0)
1563 fstretch = 0;
1564 if (fstretch > 1000)
1565 fstretch = 1000;
1566 fstretch -= (fstretch % fstep);
1567 if (fstretch < 0)
1568 fstretch = 0;
1569 set_expand_params(f, fexpand, fstretch, fshrink, fstep);
1573 } else {
1574 /* jikes, no characters */
1575 formatted_warning("font","lua-loaded font '%d' with name '%s' has no characters", f, font_name(f));
1578 if (save_ref > 0) {
1579 r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
1580 set_font_cache_id(f, r);
1581 } else {
1582 lua_pop(L, 1);
1583 set_font_cache_id(f, save_ref);
1585 } else {
1586 /* jikes, no characters */
1587 formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f));
1589 if (l_fonts != NULL)
1590 free(l_fonts);
1591 return true;
1594 @* Ligaturing.
1597 static void nesting_append(halfword nest1, halfword newn)
1599 halfword tail = tlink(nest1);
1600 if (tail == null) {
1601 couple_nodes(nest1, newn);
1602 } else {
1603 couple_nodes(tail, newn);
1605 tlink(nest1) = newn;
1608 static void nesting_prepend(halfword nest1, halfword newn)
1610 halfword head = vlink(nest1);
1611 couple_nodes(nest1, newn);
1612 if (head == null) {
1613 tlink(nest1) = newn;
1614 } else {
1615 couple_nodes(newn, head);
1619 static void nesting_prepend_list(halfword nest1, halfword newn)
1621 halfword head = vlink(nest1);
1622 couple_nodes(nest1, newn);
1623 if (head == null) {
1624 tlink(nest1) = tail_of_list(newn);
1625 } else {
1626 halfword tail = tail_of_list(newn);
1627 couple_nodes(tail, head);
1631 static int test_ligature(liginfo * lig, halfword left, halfword right)
1633 if (type(left) != glyph_node)
1634 return 0;
1635 if (font(left) != font(right))
1636 return 0;
1637 if (is_ghost(left) || is_ghost(right))
1638 return 0;
1639 *lig = get_ligature(font(left), character(left), character(right));
1640 if (is_valid_ligature(*lig)) {
1641 return 1;
1643 return 0;
1646 static int try_ligature(halfword * frst, halfword fwd)
1648 halfword cur = *frst;
1649 liginfo lig;
1650 if (test_ligature(&lig, cur, fwd)) {
1651 int move_after = (lig_type(lig) & 0x0C) >> 2;
1652 int keep_right = ((lig_type(lig) & 0x01) != 0);
1653 int keep_left = ((lig_type(lig) & 0x02) != 0);
1654 halfword newgl = raw_glyph_node();
1655 font(newgl) = font(cur);
1656 character(newgl) = lig_replacement(lig);
1657 set_is_ligature(newgl);
1659 below might not be correct in contrived border case.
1660 but we use it only for debugging, so ...
1662 if (character(cur) < 0) {
1663 set_is_leftboundary(newgl);
1665 if (character(fwd) < 0) {
1666 set_is_rightboundary(newgl);
1668 if (character(cur) < 0) {
1669 if (character(fwd) < 0) {
1670 build_attribute_list(newgl);
1671 } else {
1672 add_node_attr_ref(node_attr(fwd));
1673 node_attr(newgl) = node_attr(fwd);
1675 } else {
1676 add_node_attr_ref(node_attr(cur));
1677 node_attr(newgl) = node_attr(cur);
1681 TODO/FIXME if this ligature is consists of another ligature
1682 we should add it's |lig_ptr| to the new glyphs |lig_ptr| (and
1683 cleanup the no longer needed node) LOW PRIORITY
1685 /* left side */
1686 if (keep_left) {
1687 halfword new_first = copy_node(cur);
1688 lig_ptr(newgl) = new_first;
1689 couple_nodes(cur, newgl);
1690 if (move_after) {
1691 move_after--;
1692 cur = newgl;
1694 } else {
1695 halfword prev = alink(cur);
1696 uncouple_node(cur);
1697 lig_ptr(newgl) = cur;
1698 couple_nodes(prev, newgl);
1699 cur = newgl; /* as cur has disappeared */
1701 /* right side */
1702 if (keep_right) {
1703 halfword new_second = copy_node(fwd);
1704 /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
1705 couple_nodes(lig_ptr(newgl), new_second);
1706 couple_nodes(newgl, fwd);
1707 if (move_after) {
1708 move_after--;
1709 cur = fwd;
1711 } else {
1712 halfword next = vlink(fwd);
1713 uncouple_node(fwd);
1714 /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
1715 couple_nodes(lig_ptr(newgl), fwd);
1716 if (next != null) {
1717 couple_nodes(newgl, next);
1720 /* check and return */
1721 *frst = cur;
1722 return 1;
1724 return 0;
1727 @ there shouldn't be any ligatures here - we only add them at the end of
1728 |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing \.{DISC-1}
1729 (we continue with \.{DISC-1}'s |post_| and |no_break|.
1732 static halfword handle_lig_nest(halfword root, halfword cur)
1734 if (cur == null)
1735 return root;
1736 while (vlink(cur) != null) {
1737 halfword fwd = vlink(cur);
1738 if (type(cur) == glyph_node && type(fwd) == glyph_node &&
1739 font(cur) == font(fwd) && try_ligature(&cur, fwd)) {
1740 continue;
1742 cur = vlink(cur);
1744 tlink(root) = cur;
1745 return root;
1748 static halfword handle_lig_word(halfword cur)
1750 halfword right = null;
1751 if (type(cur) == boundary_node) {
1752 halfword prev = alink(cur);
1753 halfword fwd = vlink(cur);
1754 /* no need to uncouple |cur|, it is freed */
1755 flush_node(cur);
1756 if (fwd == null) {
1757 vlink(prev) = fwd;
1758 return prev;
1760 couple_nodes(prev, fwd);
1761 if (type(fwd) != glyph_node)
1762 return prev;
1763 cur = fwd;
1764 } else if (has_left_boundary(font(cur))) {
1765 halfword prev = alink(cur);
1766 halfword p = new_glyph(font(cur), left_boundarychar);
1767 couple_nodes(prev, p);
1768 couple_nodes(p, cur);
1769 cur = p;
1771 if (has_right_boundary(font(cur))) {
1772 right = new_glyph(font(cur), right_boundarychar);
1774 while (1) {
1775 /* A glyph followed by ... */
1776 if (type(cur) == glyph_node) {
1777 halfword fwd = vlink(cur);
1778 if (fwd == null) { /* last character of paragraph */
1779 if (right == null)
1780 break;
1781 /* \.{--\\par} prohibits use of |couple_nodes| here */
1782 try_couple_nodes(cur, right);
1783 right = null;
1784 continue;
1786 if (type(fwd) == glyph_node) { /* |GLYPH - GLYPH| */
1787 if (font(cur) != font(fwd))
1788 break;
1789 if (try_ligature(&cur, fwd))
1790 continue;
1791 } else if (type(fwd) == disc_node) { /* |GLYPH - DISC| */
1793 /* if \.{a{bx}{}{y}} and \.{a+b=>B} convert to \.{{Bx}{}{ay}} */
1794 halfword pre = vlink_pre_break(fwd);
1795 halfword nob = vlink_no_break(fwd);
1796 halfword next, tail;
1797 liginfo lig;
1798 /* Check on: a{b?}{?}{?} and a+b=>B : {B?}{?}{a?} */
1799 /* Check on: a{?}{?}{b?} and a+b=>B : {a?}{?}{B?} */
1800 if ((pre != null && type(pre) == glyph_node
1801 && test_ligature(&lig, cur, pre))
1802 || (nob != null && type(nob) == glyph_node
1803 && test_ligature(&lig, cur, nob))) {
1804 /* move cur from before disc, to skipped part */
1805 halfword prev = alink(cur);
1806 uncouple_node(cur);
1807 couple_nodes(prev, fwd);
1808 nesting_prepend(no_break(fwd), cur);
1809 /* now ligature the |pre_break| */
1810 nesting_prepend(pre_break(fwd), copy_node(cur));
1811 /* As we have removed cur, we need to start again ... */
1812 cur = prev;
1814 /* Check on: a{?}{?}{}b and a+b=>B : {a?}{?b}{B} */
1815 next = vlink(fwd);
1816 if (nob == null && next != null && type(next) == glyph_node
1817 && test_ligature(&lig, cur, next)) {
1818 /* move |cur| from before |disc| to |no_break| part */
1819 halfword prev = alink(cur);
1820 uncouple_node(cur);
1821 couple_nodes(prev, fwd);
1822 couple_nodes(no_break(fwd), cur); /* we {\it know\/} it's empty */
1823 /* now copy cur the |pre_break| */
1824 nesting_prepend(pre_break(fwd), copy_node(cur));
1825 /* move next from after disc to |no_break| part */
1826 tail = vlink(next);
1827 uncouple_node(next);
1828 try_couple_nodes(fwd, tail);
1829 couple_nodes(cur, next); /* we {\it know\/} this works */
1830 tlink(no_break(fwd)) = next; /* and make sure the list is correct */
1831 /* now copy next to the |post_break| */
1832 nesting_append(post_break(fwd), copy_node(next));
1833 /* As we have removed cur, we need to start again ... */
1834 cur = prev;
1836 /* we are finished with the |pre_break| */
1837 handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd));
1838 } else if (type(fwd) == boundary_node) {
1839 halfword next = vlink(fwd);
1840 try_couple_nodes(cur, next);
1841 flush_node(fwd);
1842 if (right != null) {
1843 flush_node(right); /* Shame, didn't need it */
1844 /* no need to reset |right|, we're going to leave the loop anyway */
1846 break;
1847 } else {
1848 /* fwd is something unknown */
1849 if (right == null)
1850 break;
1851 couple_nodes(cur, right);
1852 couple_nodes(right, fwd);
1853 right = null;
1854 continue;
1856 /* A discretionary followed by ... */
1857 } else if (type(cur) == disc_node) {
1858 /* If \.{{?}{x}{?}} or \.{{?}{?}{y}} then ... */
1859 if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
1860 halfword prev = 0;
1861 halfword fwd;
1862 liginfo lig;
1863 if (subtype(cur) == select_disc) {
1864 prev = alink(cur);
1865 if (vlink_post_break(cur) != null)
1866 handle_lig_nest(post_break(prev), vlink_post_break(prev));
1867 if (vlink_no_break(cur) != null)
1868 handle_lig_nest(no_break(prev), vlink_no_break(prev));
1870 if (vlink_post_break(cur) != null)
1871 handle_lig_nest(post_break(cur), vlink_post_break(cur));
1872 if (vlink_no_break(cur) != null)
1873 handle_lig_nest(no_break(cur), vlink_no_break(cur));
1874 while ((fwd = vlink(cur)) != null) {
1875 halfword nob, pst, next;
1876 if (type(fwd) != glyph_node)
1877 break;
1878 if (subtype(cur) != select_disc) {
1879 nob = tlink_no_break(cur);
1880 pst = tlink_post_break(cur);
1881 if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
1882 (pst == null || !test_ligature(&lig, pst, fwd)))
1883 break;
1884 nesting_append(no_break(cur), copy_node(fwd));
1885 handle_lig_nest(no_break(cur), nob);
1886 } else {
1887 int dobreak = 0;
1888 nob = tlink_no_break(prev);
1889 pst = tlink_post_break(prev);
1890 if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
1891 (pst == null || !test_ligature(&lig, pst, fwd)))
1892 dobreak = 1;
1893 if (!dobreak) {
1894 nesting_append(no_break(prev), copy_node(fwd));
1895 handle_lig_nest(no_break(prev), nob);
1896 nesting_append(post_break(prev), copy_node(fwd));
1897 handle_lig_nest(post_break(prev), pst);
1899 dobreak = 0;
1900 nob = tlink_no_break(cur);
1901 pst = tlink_post_break(cur);
1902 if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
1903 (pst == null || !test_ligature(&lig, pst, fwd)))
1904 dobreak = 1;
1905 if (!dobreak) {
1906 nesting_append(no_break(cur), copy_node(fwd));
1907 handle_lig_nest(no_break(cur), nob);
1909 if (dobreak)
1910 break;
1912 next = vlink(fwd);
1913 uncouple_node(fwd);
1914 try_couple_nodes(cur, next);
1915 nesting_append(post_break(cur), fwd);
1916 handle_lig_nest(post_break(cur), pst);
1918 if (fwd != null && type(fwd) == disc_node) {
1919 halfword next = vlink(fwd);
1920 if (vlink_no_break(fwd) == null
1921 && vlink_post_break(fwd) == null
1922 && next != null
1923 && type(next) == glyph_node
1924 && ((tlink_post_break(cur) != null && test_ligature(&lig, tlink_post_break(cur), next)) ||
1925 (tlink_no_break (cur) != null && test_ligature(&lig, tlink_no_break (cur), next)))) {
1926 /* Building an |init_disc| followed by a |select_disc|
1927 \.{{a-}{b}{AB} {-}{}{}} 'c'
1929 /* is it tail necessary ? */
1930 halfword last1 = vlink(next), tail ;
1931 uncouple_node(next);
1932 try_couple_nodes(fwd, last1);
1933 /* \.{{a-}{b}{AB} {-}{c}{}} */
1934 nesting_append(post_break(fwd), copy_node(next));
1935 /* \.{{a-}{b}{AB} {-}{c}{-}} */
1936 if (vlink_no_break(cur) != null) {
1937 nesting_prepend(no_break(fwd), copy_node(vlink_pre_break(fwd)));
1939 /* \.{{a-}{b}{AB} {b-}{c}{-}} */
1940 if (vlink_post_break(cur) != null)
1941 nesting_prepend_list(pre_break(fwd), copy_node_list(vlink_post_break(cur)));
1942 /* \.{{a-}{b}{AB} {b-}{c}{AB-}} */
1943 if (vlink_no_break(cur) != null) {
1944 nesting_prepend_list(no_break(fwd), copy_node_list(vlink_no_break(cur)));
1946 /* \.{{a-}{b}{ABC} {b-}{c}{AB-}} */
1947 tail = tlink_no_break(cur);
1948 nesting_append(no_break(cur), copy_node(next));
1949 handle_lig_nest(no_break(cur), tail);
1950 /* \.{{a-}{BC}{ABC} {b-}{c}{AB-}} */
1951 tail = tlink_post_break(cur);
1952 nesting_append(post_break(cur), next);
1953 handle_lig_nest(post_break(cur), tail);
1954 /* and set the subtypes */
1955 subtype(cur) = init_disc;
1956 subtype(fwd) = select_disc;
1961 } else {
1962 /* NO GLYPH NOR DISC */
1963 return cur;
1965 /* step-to-next-node */
1966 /* \.{--\\par} allows |vlink(cur)| to be null */
1967 cur = vlink(cur);
1970 return cur;
1973 @ Return value is the new tail, head should be a dummy
1976 halfword handle_ligaturing(halfword head, halfword tail)
1978 halfword save_tail1; /* trick to allow explicit |node==null| tests */
1979 halfword cur, prev;
1981 if (vlink(head) == null)
1982 return tail;
1983 save_tail1 = vlink(tail);
1984 vlink(tail) = null;
1986 /* |if (fix_node_lists)| */
1987 fix_node_list(head);
1989 prev = head;
1990 cur = vlink(prev);
1992 while (cur != null) {
1993 if (type(cur) == glyph_node || (type(cur) == boundary_node)) {
1994 cur = handle_lig_word(cur);
1996 prev = cur;
1997 cur = vlink(cur);
1999 if (prev == null)
2000 prev = tail;
2002 if (valid_node(save_tail1)) {
2003 try_couple_nodes(prev, save_tail1);
2005 return prev;
2009 @* Kerning.
2012 static void add_kern_before(halfword left, halfword right)
2014 if ((!is_rightghost(right)) &&
2015 font(left) == font(right) && has_kern(font(left), character(left))) {
2016 int k = raw_get_kern(font(left), character(left), character(right));
2017 if (k != 0) {
2018 halfword kern = new_kern(k);
2019 halfword prev = alink(right);
2020 couple_nodes(prev, kern);
2021 couple_nodes(kern, right);
2022 /* update the attribute list (inherit from left) */
2023 delete_attribute_ref(node_attr(kern));
2024 add_node_attr_ref(node_attr(left));
2025 node_attr(kern) = node_attr(left);
2030 static void add_kern_after(halfword left, halfword right, halfword aft)
2032 if ((!is_rightghost(right)) &&
2033 font(left) == font(right) && has_kern(font(left), character(left))) {
2034 int k = raw_get_kern(font(left), character(left), character(right));
2035 if (k != 0) {
2036 halfword kern = new_kern(k);
2037 halfword next = vlink(aft);
2038 couple_nodes(aft, kern);
2039 try_couple_nodes(kern, next);
2040 /* update the attribute list (inherit from left == aft) */
2041 delete_attribute_ref(node_attr(kern));
2042 add_node_attr_ref(node_attr(aft));
2043 node_attr(kern) = node_attr(aft);
2048 static void do_handle_kerning(halfword root, halfword init_left, halfword init_right)
2050 halfword cur = vlink(root);
2051 halfword left = null;
2052 if (cur == null) {
2053 if (init_left != null && init_right != null) {
2054 add_kern_after(init_left, init_right, root);
2055 tlink(root) = vlink(root);
2057 return;
2059 if (type(cur) == glyph_node) {
2060 set_is_glyph(cur);
2061 if (init_left != null)
2062 add_kern_before(init_left, cur);
2063 left = cur;
2065 while ((cur = vlink(cur)) != null) {
2066 if (type(cur) == glyph_node) {
2067 set_is_glyph(cur);
2068 if (left != null) {
2069 add_kern_before(left, cur);
2070 if (character(left) < 0 || is_ghost(left)) {
2071 halfword prev = alink(left);
2072 couple_nodes(prev, cur);
2073 flush_node(left);
2076 left = cur;
2077 } else {
2078 if (type(cur) == disc_node) {
2079 halfword right = type(vlink(cur)) == glyph_node ? vlink(cur) : null;
2080 do_handle_kerning(pre_break(cur), left, null);
2081 do_handle_kerning(post_break(cur), null, right);
2082 if (vlink_post_break(cur) != null)
2083 tlink_post_break(cur) = tail_of_list(vlink_post_break(cur));
2084 do_handle_kerning(no_break(cur), left, right);
2085 if (vlink_no_break(cur) != null)
2086 tlink_no_break(cur) = tail_of_list(vlink_no_break(cur)); /* needed? */
2088 if (left != null) {
2089 if (character(left) < 0 || is_ghost(left)) {
2090 halfword prev = alink(left);
2091 couple_nodes(prev, cur);
2092 flush_node(left);
2094 left = null;
2098 if (left != null) {
2099 if (init_right != null)
2100 add_kern_after(left, init_right, left);
2101 if (character(left) < 0 || is_ghost(left)) {
2102 halfword prev = alink(left);
2103 halfword next = vlink(left);
2104 if (next != null) {
2105 couple_nodes(prev, next);
2106 tlink(root) = next;
2107 } else if (prev != root) {
2108 vlink(prev) = null;
2109 tlink(root) = prev;
2110 } else {
2111 vlink(root) = null;
2112 tlink(root) = null;
2114 flush_node(left);
2119 halfword handle_kerning(halfword head, halfword tail)
2121 halfword save_link;
2122 save_link = vlink(tail);
2123 vlink(tail) = null;
2124 tlink(head) = tail;
2125 do_handle_kerning(head, null, null);
2126 tail = tlink(head);
2127 if (valid_node(save_link)) {
2128 try_couple_nodes(tail, save_link);
2130 return tail;
2133 @* ligaturing and kerning : lua-interface.
2136 static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callback_id)
2138 lua_State *L = Luas;
2139 int i;
2140 int top = lua_gettop(L);
2141 if (!get_callback(L, callback_id)) {
2142 lua_pop(L, 2);
2143 return tail;
2145 nodelist_to_lua(L, head);
2146 nodelist_to_lua(L, tail);
2147 if ((i=lua_pcall(L, 2, 0, 0)) != 0) {
2148 luatex_error(L, (i == LUA_ERRRUN ? 0 : 1));
2149 return tail;
2151 fix_node_list(head);
2152 lua_settop(L, top);
2153 return tail;
2156 halfword new_ligkern(halfword head, halfword tail)
2158 int callback_id = 0;
2159 if (vlink(head) == null)
2160 return tail;
2161 callback_id = callback_defined(ligaturing_callback);
2162 if (callback_id > 0) {
2163 tail = run_lua_ligkern_callback(head, tail, callback_id);
2164 if (tail == null)
2165 tail = tail_of_list(head);
2166 } else if (callback_id == 0) {
2167 tail = handle_ligaturing(head, tail);
2169 callback_id = callback_defined(kerning_callback);
2170 if (callback_id > 0) {
2171 tail = run_lua_ligkern_callback(head, tail, callback_id);
2172 if (tail == null) {
2173 tail = tail_of_list(head);
2175 } else if (callback_id == 0) {
2176 halfword nest1 = new_node(nesting_node, 1);
2177 halfword cur = vlink(head);
2178 halfword aft = vlink(tail);
2179 couple_nodes(nest1, cur);
2180 tlink(nest1) = tail;
2181 vlink(tail) = null;
2182 do_handle_kerning(nest1, null, null);
2183 couple_nodes(head, vlink(nest1));
2184 tail = tlink(nest1);
2185 try_couple_nodes(tail, aft);
2186 flush_node(nest1);
2188 return tail;