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