1 /* $NetBSD: node.cpp,v 1.2 2016/01/13 19:01:59 christos Exp $ */ 2 3 // -*- C++ -*- 4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005 5 Free Software Foundation, Inc. 6 Written by James Clark (jjc@jclark.com) 7 8 This file is part of groff. 9 10 groff is free software; you can redistribute it and/or modify it under 11 the terms of the GNU General Public License as published by the Free 12 Software Foundation; either version 2, or (at your option) any later 13 version. 14 15 groff is distributed in the hope that it will be useful, but WITHOUT ANY 16 WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 for more details. 19 20 You should have received a copy of the GNU General Public License along 21 with groff; see the file COPYING. If not, write to the Free Software 22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 23 24 extern int debug_state; 25 26 #include "troff.h" 27 28 #ifdef HAVE_UNISTD_H 29 #include <unistd.h> 30 #endif 31 32 #include "dictionary.h" 33 #include "hvunits.h" 34 #include "stringclass.h" 35 #include "mtsm.h" 36 #include "env.h" 37 #include "request.h" 38 #include "node.h" 39 #include "token.h" 40 #include "div.h" 41 #include "reg.h" 42 #include "charinfo.h" 43 #include "font.h" 44 #include "input.h" 45 #include "geometry.h" 46 47 #include "nonposix.h" 48 49 #ifdef _POSIX_VERSION 50 51 #include <sys/wait.h> 52 53 #else /* not _POSIX_VERSION */ 54 55 /* traditional Unix */ 56 57 #define WIFEXITED(s) (((s) & 0377) == 0) 58 #define WEXITSTATUS(s) (((s) >> 8) & 0377) 59 #define WTERMSIG(s) ((s) & 0177) 60 #define WIFSTOPPED(s) (((s) & 0377) == 0177) 61 #define WSTOPSIG(s) (((s) >> 8) & 0377) 62 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177)) 63 64 #endif /* not _POSIX_VERSION */ 65 66 // declarations to avoid friend name injections 67 class tfont; 68 class tfont_spec; 69 tfont *make_tfont(tfont_spec &); 70 71 72 /* 73 * how many boundaries of images have been written? Useful for 74 * debugging grohtml 75 */ 76 77 int image_no = 0; 78 static int suppress_start_page = 0; 79 80 #define STORE_WIDTH 1 81 82 symbol HYPHEN_SYMBOL("hy"); 83 84 // Character used when a hyphen is inserted at a line break. 85 static charinfo *soft_hyphen_char; 86 87 enum constant_space_type { 88 CONSTANT_SPACE_NONE, 89 CONSTANT_SPACE_RELATIVE, 90 CONSTANT_SPACE_ABSOLUTE 91 }; 92 93 struct special_font_list { 94 int n; 95 special_font_list *next; 96 }; 97 98 special_font_list *global_special_fonts; 99 static int global_ligature_mode = 1; 100 static int global_kern_mode = 1; 101 102 class track_kerning_function { 103 int non_zero; 104 units min_size; 105 hunits min_amount; 106 units max_size; 107 hunits max_amount; 108 public: 109 track_kerning_function(); 110 track_kerning_function(units, hunits, units, hunits); 111 int operator==(const track_kerning_function &); 112 int operator!=(const track_kerning_function &); 113 hunits compute(int point_size); 114 }; 115 116 // embolden fontno when this is the current font 117 118 struct conditional_bold { 119 conditional_bold *next; 120 int fontno; 121 hunits offset; 122 conditional_bold(int, hunits, conditional_bold * = 0); 123 }; 124 125 class font_info { 126 tfont *last_tfont; 127 int number; 128 font_size last_size; 129 int last_height; 130 int last_slant; 131 symbol internal_name; 132 symbol external_name; 133 font *fm; 134 char is_bold; 135 hunits bold_offset; 136 track_kerning_function track_kern; 137 constant_space_type is_constant_spaced; 138 units constant_space; 139 int last_ligature_mode; 140 int last_kern_mode; 141 conditional_bold *cond_bold_list; 142 void flush(); 143 public: 144 special_font_list *sf; 145 font_info(symbol, int, symbol, font *); 146 int contains(charinfo *); 147 void set_bold(hunits); 148 void unbold(); 149 void set_conditional_bold(int, hunits); 150 void conditional_unbold(int); 151 void set_track_kern(track_kerning_function &); 152 void set_constant_space(constant_space_type, units = 0); 153 int is_named(symbol); 154 symbol get_name(); 155 tfont *get_tfont(font_size, int, int, int); 156 hunits get_space_width(font_size, int); 157 hunits get_narrow_space_width(font_size); 158 hunits get_half_narrow_space_width(font_size); 159 int get_bold(hunits *); 160 int is_special(); 161 int is_style(); 162 friend symbol get_font_name(int, environment *); 163 friend symbol get_style_name(int); 164 }; 165 166 class tfont_spec { 167 protected: 168 symbol name; 169 int input_position; 170 font *fm; 171 font_size size; 172 char is_bold; 173 char is_constant_spaced; 174 int ligature_mode; 175 int kern_mode; 176 hunits bold_offset; 177 hunits track_kern; // add this to the width 178 hunits constant_space_width; 179 int height; 180 int slant; 181 public: 182 tfont_spec(symbol, int, font *, font_size, int, int); 183 tfont_spec(const tfont_spec &spec) { *this = spec; } 184 tfont_spec plain(); 185 int operator==(const tfont_spec &); 186 friend tfont *font_info::get_tfont(font_size fs, int, int, int); 187 }; 188 189 class tfont : public tfont_spec { 190 static tfont *tfont_list; 191 tfont *next; 192 tfont *plain_version; 193 public: 194 tfont(tfont_spec &); 195 int contains(charinfo *); 196 hunits get_width(charinfo *c); 197 int get_bold(hunits *); 198 int get_constant_space(hunits *); 199 hunits get_track_kern(); 200 tfont *get_plain(); 201 font_size get_size(); 202 symbol get_name(); 203 charinfo *get_lig(charinfo *c1, charinfo *c2); 204 int get_kern(charinfo *c1, charinfo *c2, hunits *res); 205 int get_input_position(); 206 int get_character_type(charinfo *); 207 int get_height(); 208 int get_slant(); 209 vunits get_char_height(charinfo *); 210 vunits get_char_depth(charinfo *); 211 hunits get_char_skew(charinfo *); 212 hunits get_italic_correction(charinfo *); 213 hunits get_left_italic_correction(charinfo *); 214 hunits get_subscript_correction(charinfo *); 215 friend tfont *make_tfont(tfont_spec &); 216 }; 217 218 inline int env_definite_font(environment *env) 219 { 220 return env->get_family()->make_definite(env->get_font()); 221 } 222 223 /* font_info functions */ 224 225 static font_info **font_table = 0; 226 static int font_table_size = 0; 227 228 font_info::font_info(symbol nm, int n, symbol enm, font *f) 229 : last_tfont(0), number(n), last_size(0), 230 internal_name(nm), external_name(enm), fm(f), 231 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1), 232 last_kern_mode(1), cond_bold_list(0), sf(0) 233 { 234 } 235 236 inline int font_info::contains(charinfo *ci) 237 { 238 return fm != 0 && fm->contains(ci->get_index()); 239 } 240 241 inline int font_info::is_special() 242 { 243 return fm != 0 && fm->is_special(); 244 } 245 246 inline int font_info::is_style() 247 { 248 return fm == 0; 249 } 250 251 tfont *make_tfont(tfont_spec &spec) 252 { 253 for (tfont *p = tfont::tfont_list; p; p = p->next) 254 if (*p == spec) 255 return p; 256 return new tfont(spec); 257 } 258 259 // this is the current_font, fontno is where we found the character, 260 // presumably a special font 261 262 tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno) 263 { 264 if (last_tfont == 0 || fs != last_size 265 || height != last_height || slant != last_slant 266 || global_ligature_mode != last_ligature_mode 267 || global_kern_mode != last_kern_mode 268 || fontno != number) { 269 font_info *f = font_table[fontno]; 270 tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant); 271 for (conditional_bold *p = cond_bold_list; p; p = p->next) 272 if (p->fontno == fontno) { 273 spec.is_bold = 1; 274 spec.bold_offset = p->offset; 275 break; 276 } 277 if (!spec.is_bold && is_bold) { 278 spec.is_bold = 1; 279 spec.bold_offset = bold_offset; 280 } 281 spec.track_kern = track_kern.compute(fs.to_scaled_points()); 282 spec.ligature_mode = global_ligature_mode; 283 spec.kern_mode = global_kern_mode; 284 switch (is_constant_spaced) { 285 case CONSTANT_SPACE_NONE: 286 break; 287 case CONSTANT_SPACE_ABSOLUTE: 288 spec.is_constant_spaced = 1; 289 spec.constant_space_width = constant_space; 290 break; 291 case CONSTANT_SPACE_RELATIVE: 292 spec.is_constant_spaced = 1; 293 spec.constant_space_width 294 = scale(constant_space*fs.to_scaled_points(), 295 units_per_inch, 296 36*72*sizescale); 297 break; 298 default: 299 assert(0); 300 } 301 if (fontno != number) 302 return make_tfont(spec); 303 last_tfont = make_tfont(spec); 304 last_size = fs; 305 last_height = height; 306 last_slant = slant; 307 last_ligature_mode = global_ligature_mode; 308 last_kern_mode = global_kern_mode; 309 } 310 return last_tfont; 311 } 312 313 int font_info::get_bold(hunits *res) 314 { 315 if (is_bold) { 316 *res = bold_offset; 317 return 1; 318 } 319 else 320 return 0; 321 } 322 323 void font_info::unbold() 324 { 325 if (is_bold) { 326 is_bold = 0; 327 flush(); 328 } 329 } 330 331 void font_info::set_bold(hunits offset) 332 { 333 if (!is_bold || offset != bold_offset) { 334 is_bold = 1; 335 bold_offset = offset; 336 flush(); 337 } 338 } 339 340 void font_info::set_conditional_bold(int fontno, hunits offset) 341 { 342 for (conditional_bold *p = cond_bold_list; p; p = p->next) 343 if (p->fontno == fontno) { 344 if (offset != p->offset) { 345 p->offset = offset; 346 flush(); 347 } 348 return; 349 } 350 cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list); 351 } 352 353 conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x) 354 : next(x), fontno(f), offset(h) 355 { 356 } 357 358 void font_info::conditional_unbold(int fontno) 359 { 360 for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next) 361 if ((*p)->fontno == fontno) { 362 conditional_bold *tem = *p; 363 *p = (*p)->next; 364 delete tem; 365 flush(); 366 return; 367 } 368 } 369 370 void font_info::set_constant_space(constant_space_type type, units x) 371 { 372 if (type != is_constant_spaced 373 || (type != CONSTANT_SPACE_NONE && x != constant_space)) { 374 flush(); 375 is_constant_spaced = type; 376 constant_space = x; 377 } 378 } 379 380 void font_info::set_track_kern(track_kerning_function &tk) 381 { 382 if (track_kern != tk) { 383 track_kern = tk; 384 flush(); 385 } 386 } 387 388 void font_info::flush() 389 { 390 last_tfont = 0; 391 } 392 393 int font_info::is_named(symbol s) 394 { 395 return internal_name == s; 396 } 397 398 symbol font_info::get_name() 399 { 400 return internal_name; 401 } 402 403 symbol get_font_name(int fontno, environment *env) 404 { 405 symbol f = font_table[fontno]->get_name(); 406 if (font_table[fontno]->is_style()) { 407 return concat(env->get_family()->nm, f); 408 } 409 return f; 410 } 411 412 symbol get_style_name(int fontno) 413 { 414 if (font_table[fontno]->is_style()) 415 return font_table[fontno]->get_name(); 416 else 417 return EMPTY_SYMBOL; 418 } 419 420 hunits font_info::get_space_width(font_size fs, int space_sz) 421 { 422 if (is_constant_spaced == CONSTANT_SPACE_NONE) 423 return scale(hunits(fm->get_space_width(fs.to_scaled_points())), 424 space_sz, 12); 425 else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE) 426 return constant_space; 427 else 428 return scale(constant_space*fs.to_scaled_points(), 429 units_per_inch, 36*72*sizescale); 430 } 431 432 hunits font_info::get_narrow_space_width(font_size fs) 433 { 434 charinfo *ci = get_charinfo(symbol("|")); 435 if (fm->contains(ci->get_index())) 436 return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); 437 else 438 return hunits(fs.to_units()/6); 439 } 440 441 hunits font_info::get_half_narrow_space_width(font_size fs) 442 { 443 charinfo *ci = get_charinfo(symbol("^")); 444 if (fm->contains(ci->get_index())) 445 return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); 446 else 447 return hunits(fs.to_units()/12); 448 } 449 450 /* tfont */ 451 452 tfont_spec::tfont_spec(symbol nm, int n, font *f, 453 font_size s, int h, int sl) 454 : name(nm), input_position(n), fm(f), size(s), 455 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1), 456 height(h), slant(sl) 457 { 458 if (height == size.to_scaled_points()) 459 height = 0; 460 } 461 462 int tfont_spec::operator==(const tfont_spec &spec) 463 { 464 if (fm == spec.fm 465 && size == spec.size 466 && input_position == spec.input_position 467 && name == spec.name 468 && height == spec.height 469 && slant == spec.slant 470 && (is_bold 471 ? (spec.is_bold && bold_offset == spec.bold_offset) 472 : !spec.is_bold) 473 && track_kern == spec.track_kern 474 && (is_constant_spaced 475 ? (spec.is_constant_spaced 476 && constant_space_width == spec.constant_space_width) 477 : !spec.is_constant_spaced) 478 && ligature_mode == spec.ligature_mode 479 && kern_mode == spec.kern_mode) 480 return 1; 481 else 482 return 0; 483 } 484 485 tfont_spec tfont_spec::plain() 486 { 487 return tfont_spec(name, input_position, fm, size, height, slant); 488 } 489 490 hunits tfont::get_width(charinfo *c) 491 { 492 if (is_constant_spaced) 493 return constant_space_width; 494 else if (is_bold) 495 return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) 496 + track_kern + bold_offset); 497 else 498 return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) 499 + track_kern); 500 } 501 502 vunits tfont::get_char_height(charinfo *c) 503 { 504 vunits v = fm->get_height(c->get_index(), size.to_scaled_points()); 505 if (height != 0 && height != size.to_scaled_points()) 506 return scale(v, height, size.to_scaled_points()); 507 else 508 return v; 509 } 510 511 vunits tfont::get_char_depth(charinfo *c) 512 { 513 vunits v = fm->get_depth(c->get_index(), size.to_scaled_points()); 514 if (height != 0 && height != size.to_scaled_points()) 515 return scale(v, height, size.to_scaled_points()); 516 else 517 return v; 518 } 519 520 hunits tfont::get_char_skew(charinfo *c) 521 { 522 return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant)); 523 } 524 525 hunits tfont::get_italic_correction(charinfo *c) 526 { 527 return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points())); 528 } 529 530 hunits tfont::get_left_italic_correction(charinfo *c) 531 { 532 return hunits(fm->get_left_italic_correction(c->get_index(), 533 size.to_scaled_points())); 534 } 535 536 hunits tfont::get_subscript_correction(charinfo *c) 537 { 538 return hunits(fm->get_subscript_correction(c->get_index(), 539 size.to_scaled_points())); 540 } 541 542 inline int tfont::get_input_position() 543 { 544 return input_position; 545 } 546 547 inline int tfont::contains(charinfo *ci) 548 { 549 return fm->contains(ci->get_index()); 550 } 551 552 inline int tfont::get_character_type(charinfo *ci) 553 { 554 return fm->get_character_type(ci->get_index()); 555 } 556 557 inline int tfont::get_bold(hunits *res) 558 { 559 if (is_bold) { 560 *res = bold_offset; 561 return 1; 562 } 563 else 564 return 0; 565 } 566 567 inline int tfont::get_constant_space(hunits *res) 568 { 569 if (is_constant_spaced) { 570 *res = constant_space_width; 571 return 1; 572 } 573 else 574 return 0; 575 } 576 577 inline hunits tfont::get_track_kern() 578 { 579 return track_kern; 580 } 581 582 inline tfont *tfont::get_plain() 583 { 584 return plain_version; 585 } 586 587 inline font_size tfont::get_size() 588 { 589 return size; 590 } 591 592 inline symbol tfont::get_name() 593 { 594 return name; 595 } 596 597 inline int tfont::get_height() 598 { 599 return height; 600 } 601 602 inline int tfont::get_slant() 603 { 604 return slant; 605 } 606 607 symbol SYMBOL_ff("ff"); 608 symbol SYMBOL_fi("fi"); 609 symbol SYMBOL_fl("fl"); 610 symbol SYMBOL_Fi("Fi"); 611 symbol SYMBOL_Fl("Fl"); 612 613 charinfo *tfont::get_lig(charinfo *c1, charinfo *c2) 614 { 615 if (ligature_mode == 0) 616 return 0; 617 charinfo *ci = 0; 618 if (c1->get_ascii_code() == 'f') { 619 switch (c2->get_ascii_code()) { 620 case 'f': 621 if (fm->has_ligature(font::LIG_ff)) 622 ci = get_charinfo(SYMBOL_ff); 623 break; 624 case 'i': 625 if (fm->has_ligature(font::LIG_fi)) 626 ci = get_charinfo(SYMBOL_fi); 627 break; 628 case 'l': 629 if (fm->has_ligature(font::LIG_fl)) 630 ci = get_charinfo(SYMBOL_fl); 631 break; 632 } 633 } 634 else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) { 635 switch (c2->get_ascii_code()) { 636 case 'i': 637 if (fm->has_ligature(font::LIG_ffi)) 638 ci = get_charinfo(SYMBOL_Fi); 639 break; 640 case 'l': 641 if (fm->has_ligature(font::LIG_ffl)) 642 ci = get_charinfo(SYMBOL_Fl); 643 break; 644 } 645 } 646 if (ci != 0 && fm->contains(ci->get_index())) 647 return ci; 648 return 0; 649 } 650 651 inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res) 652 { 653 if (kern_mode == 0) 654 return 0; 655 else { 656 int n = fm->get_kern(c1->get_index(), 657 c2->get_index(), 658 size.to_scaled_points()); 659 if (n) { 660 *res = hunits(n); 661 return 1; 662 } 663 else 664 return 0; 665 } 666 } 667 668 tfont *tfont::tfont_list = 0; 669 670 tfont::tfont(tfont_spec &spec) : tfont_spec(spec) 671 { 672 next = tfont_list; 673 tfont_list = this; 674 tfont_spec plain_spec = plain(); 675 tfont *p; 676 for (p = tfont_list; p; p = p->next) 677 if (*p == plain_spec) { 678 plain_version = p; 679 break; 680 } 681 if (!p) 682 plain_version = new tfont(plain_spec); 683 } 684 685 /* output_file */ 686 687 class real_output_file : public output_file { 688 #ifndef POPEN_MISSING 689 int piped; 690 #endif 691 int printing; // decision via optional page list 692 int output_on; // \O[0] or \O[1] escape calls 693 virtual void really_transparent_char(unsigned char) = 0; 694 virtual void really_print_line(hunits x, vunits y, node *n, 695 vunits before, vunits after, hunits width) = 0; 696 virtual void really_begin_page(int pageno, vunits page_length) = 0; 697 virtual void really_copy_file(hunits x, vunits y, const char *filename); 698 virtual void really_put_filename(const char *filename); 699 virtual void really_on(); 700 virtual void really_off(); 701 public: 702 FILE *fp; 703 real_output_file(); 704 ~real_output_file(); 705 void flush(); 706 void transparent_char(unsigned char); 707 void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width); 708 void begin_page(int pageno, vunits page_length); 709 void put_filename(const char *filename); 710 void on(); 711 void off(); 712 int is_on(); 713 int is_printing(); 714 void copy_file(hunits x, vunits y, const char *filename); 715 }; 716 717 class suppress_output_file : public real_output_file { 718 public: 719 suppress_output_file(); 720 void really_transparent_char(unsigned char); 721 void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width); 722 void really_begin_page(int pageno, vunits page_length); 723 }; 724 725 class ascii_output_file : public real_output_file { 726 public: 727 ascii_output_file(); 728 void really_transparent_char(unsigned char); 729 void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width); 730 void really_begin_page(int pageno, vunits page_length); 731 void outc(unsigned char c); 732 void outs(const char *s); 733 }; 734 735 void ascii_output_file::outc(unsigned char c) 736 { 737 fputc(c, fp); 738 } 739 740 void ascii_output_file::outs(const char *s) 741 { 742 fputc('<', fp); 743 if (s) 744 fputs(s, fp); 745 fputc('>', fp); 746 } 747 748 struct hvpair; 749 750 class troff_output_file : public real_output_file { 751 units hpos; 752 units vpos; 753 units output_vpos; 754 units output_hpos; 755 int force_motion; 756 int current_size; 757 int current_slant; 758 int current_height; 759 tfont *current_tfont; 760 color *current_fill_color; 761 color *current_glyph_color; 762 int current_font_number; 763 symbol *font_position; 764 int nfont_positions; 765 enum { TBUF_SIZE = 256 }; 766 char tbuf[TBUF_SIZE]; 767 int tbuf_len; 768 int tbuf_kern; 769 int begun_page; 770 int cur_div_level; 771 string tag_list; 772 void do_motion(); 773 void put(char c); 774 void put(unsigned char c); 775 void put(int i); 776 void put(unsigned int i); 777 void put(const char *s); 778 void set_font(tfont *tf); 779 void flush_tbuf(); 780 public: 781 troff_output_file(); 782 ~troff_output_file(); 783 void trailer(vunits page_length); 784 void put_char(charinfo *, tfont *, color *, color *); 785 void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits); 786 void right(hunits); 787 void down(vunits); 788 void moveto(hunits, vunits); 789 void start_special(tfont *, color *, color *, int = 0); 790 void start_special(); 791 void special_char(unsigned char c); 792 void end_special(); 793 void word_marker(); 794 void really_transparent_char(unsigned char c); 795 void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width); 796 void really_begin_page(int pageno, vunits page_length); 797 void really_copy_file(hunits x, vunits y, const char *filename); 798 void really_put_filename(const char *filename); 799 void really_on(); 800 void really_off(); 801 void draw(char, hvpair *, int, font_size, color *, color *); 802 void determine_line_limits (char code, hvpair *point, int npoints); 803 void check_charinfo(tfont *tf, charinfo *ci); 804 void glyph_color(color *c); 805 void fill_color(color *c); 806 int get_hpos() { return hpos; } 807 int get_vpos() { return vpos; } 808 void add_to_tag_list(string s); 809 friend void space_char_hmotion_node::tprint(troff_output_file *); 810 friend void unbreakable_space_node::tprint(troff_output_file *); 811 }; 812 813 static void put_string(const char *s, FILE *fp) 814 { 815 for (; *s != '\0'; ++s) 816 putc(*s, fp); 817 } 818 819 inline void troff_output_file::put(char c) 820 { 821 putc(c, fp); 822 } 823 824 inline void troff_output_file::put(unsigned char c) 825 { 826 putc(c, fp); 827 } 828 829 inline void troff_output_file::put(const char *s) 830 { 831 put_string(s, fp); 832 } 833 834 inline void troff_output_file::put(int i) 835 { 836 put_string(i_to_a(i), fp); 837 } 838 839 inline void troff_output_file::put(unsigned int i) 840 { 841 put_string(ui_to_a(i), fp); 842 } 843 844 void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol, 845 int no_init_string) 846 { 847 set_font(tf); 848 glyph_color(gcol); 849 fill_color(fcol); 850 flush_tbuf(); 851 do_motion(); 852 if (!no_init_string) 853 put("x X "); 854 } 855 856 void troff_output_file::start_special() 857 { 858 flush_tbuf(); 859 do_motion(); 860 put("x X "); 861 } 862 863 void troff_output_file::special_char(unsigned char c) 864 { 865 put(c); 866 if (c == '\n') 867 put('+'); 868 } 869 870 void troff_output_file::end_special() 871 { 872 put('\n'); 873 } 874 875 inline void troff_output_file::moveto(hunits h, vunits v) 876 { 877 hpos = h.to_units(); 878 vpos = v.to_units(); 879 } 880 881 void troff_output_file::really_print_line(hunits x, vunits y, node *n, 882 vunits before, vunits after, hunits) 883 { 884 moveto(x, y); 885 while (n != 0) { 886 // Check whether we should push the current troff state and use 887 // the state at the start of the invocation of this diversion. 888 if (n->div_nest_level > cur_div_level && n->push_state) { 889 state.push_state(n->push_state); 890 cur_div_level = n->div_nest_level; 891 } 892 // Has the current diversion level decreased? Then we must pop the 893 // troff state. 894 while (n->div_nest_level < cur_div_level) { 895 state.pop_state(); 896 cur_div_level = n->div_nest_level; 897 } 898 // Now check whether the state has changed. 899 if ((is_on() || n->force_tprint()) 900 && (state.changed(n->state) || n->is_tag() || n->is_special)) { 901 flush_tbuf(); 902 do_motion(); 903 force_motion = 1; 904 flush(); 905 state.flush(fp, n->state, tag_list); 906 tag_list = string(""); 907 flush(); 908 } 909 n->tprint(this); 910 n = n->next; 911 } 912 flush_tbuf(); 913 // This ensures that transparent throughput will have a more predictable 914 // position. 915 do_motion(); 916 force_motion = 1; 917 hpos = 0; 918 put('n'); 919 put(before.to_units()); 920 put(' '); 921 put(after.to_units()); 922 put('\n'); 923 } 924 925 inline void troff_output_file::word_marker() 926 { 927 flush_tbuf(); 928 if (is_on()) 929 put('w'); 930 } 931 932 inline void troff_output_file::right(hunits n) 933 { 934 hpos += n.to_units(); 935 } 936 937 inline void troff_output_file::down(vunits n) 938 { 939 vpos += n.to_units(); 940 } 941 942 void troff_output_file::do_motion() 943 { 944 if (force_motion) { 945 put('V'); 946 put(vpos); 947 put('\n'); 948 put('H'); 949 put(hpos); 950 put('\n'); 951 } 952 else { 953 if (hpos != output_hpos) { 954 units n = hpos - output_hpos; 955 if (n > 0 && n < hpos) { 956 put('h'); 957 put(n); 958 } 959 else { 960 put('H'); 961 put(hpos); 962 } 963 put('\n'); 964 } 965 if (vpos != output_vpos) { 966 units n = vpos - output_vpos; 967 if (n > 0 && n < vpos) { 968 put('v'); 969 put(n); 970 } 971 else { 972 put('V'); 973 put(vpos); 974 } 975 put('\n'); 976 } 977 } 978 output_vpos = vpos; 979 output_hpos = hpos; 980 force_motion = 0; 981 } 982 983 void troff_output_file::flush_tbuf() 984 { 985 if (!is_on()) { 986 tbuf_len = 0; 987 return; 988 } 989 990 if (tbuf_len == 0) 991 return; 992 if (tbuf_kern == 0) 993 put('t'); 994 else { 995 put('u'); 996 put(tbuf_kern); 997 put(' '); 998 } 999 check_output_limits(hpos, vpos); 1000 check_output_limits(hpos, vpos - current_size); 1001 1002 for (int i = 0; i < tbuf_len; i++) 1003 put(tbuf[i]); 1004 put('\n'); 1005 tbuf_len = 0; 1006 } 1007 1008 void troff_output_file::check_charinfo(tfont *tf, charinfo *ci) 1009 { 1010 if (!is_on()) 1011 return; 1012 1013 int height = tf->get_char_height(ci).to_units(); 1014 int width = tf->get_width(ci).to_units() 1015 + tf->get_italic_correction(ci).to_units(); 1016 int depth = tf->get_char_depth(ci).to_units(); 1017 check_output_limits(output_hpos, output_vpos - height); 1018 check_output_limits(output_hpos + width, output_vpos + depth); 1019 } 1020 1021 void troff_output_file::put_char_width(charinfo *ci, tfont *tf, 1022 color *gcol, color *fcol, 1023 hunits w, hunits k) 1024 { 1025 int kk = k.to_units(); 1026 if (!is_on()) { 1027 flush_tbuf(); 1028 hpos += w.to_units() + kk; 1029 return; 1030 } 1031 set_font(tf); 1032 unsigned char c = ci->get_ascii_code(); 1033 if (c == '\0') { 1034 glyph_color(gcol); 1035 fill_color(fcol); 1036 flush_tbuf(); 1037 do_motion(); 1038 check_charinfo(tf, ci); 1039 if (ci->numbered()) { 1040 put('N'); 1041 put(ci->get_number()); 1042 } 1043 else { 1044 put('C'); 1045 const char *s = ci->nm.contents(); 1046 if (s[1] == 0) { 1047 put('\\'); 1048 put(s[0]); 1049 } 1050 else 1051 put(s); 1052 } 1053 put('\n'); 1054 hpos += w.to_units() + kk; 1055 } 1056 else if (tcommand_flag) { 1057 if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos 1058 && (!gcol || gcol == current_glyph_color) 1059 && (!fcol || fcol == current_fill_color) 1060 && kk == tbuf_kern 1061 && tbuf_len < TBUF_SIZE) { 1062 check_charinfo(tf, ci); 1063 tbuf[tbuf_len++] = c; 1064 output_hpos += w.to_units() + kk; 1065 hpos = output_hpos; 1066 return; 1067 } 1068 glyph_color(gcol); 1069 fill_color(fcol); 1070 flush_tbuf(); 1071 do_motion(); 1072 check_charinfo(tf, ci); 1073 tbuf[tbuf_len++] = c; 1074 output_hpos += w.to_units() + kk; 1075 tbuf_kern = kk; 1076 hpos = output_hpos; 1077 } 1078 else { 1079 // flush_tbuf(); 1080 int n = hpos - output_hpos; 1081 check_charinfo(tf, ci); 1082 // check_output_limits(output_hpos, output_vpos); 1083 if (vpos == output_vpos 1084 && (!gcol || gcol == current_glyph_color) 1085 && (!fcol || fcol == current_fill_color) 1086 && n > 0 && n < 100 && !force_motion) { 1087 put(char(n/10 + '0')); 1088 put(char(n%10 + '0')); 1089 put(c); 1090 output_hpos = hpos; 1091 } 1092 else { 1093 glyph_color(gcol); 1094 fill_color(fcol); 1095 do_motion(); 1096 put('c'); 1097 put(c); 1098 } 1099 hpos += w.to_units() + kk; 1100 } 1101 } 1102 1103 void troff_output_file::put_char(charinfo *ci, tfont *tf, 1104 color *gcol, color *fcol) 1105 { 1106 flush_tbuf(); 1107 if (!is_on()) 1108 return; 1109 set_font(tf); 1110 unsigned char c = ci->get_ascii_code(); 1111 if (c == '\0') { 1112 glyph_color(gcol); 1113 fill_color(fcol); 1114 flush_tbuf(); 1115 do_motion(); 1116 if (ci->numbered()) { 1117 put('N'); 1118 put(ci->get_number()); 1119 } 1120 else { 1121 put('C'); 1122 const char *s = ci->nm.contents(); 1123 if (s[1] == 0) { 1124 put('\\'); 1125 put(s[0]); 1126 } 1127 else 1128 put(s); 1129 } 1130 put('\n'); 1131 } 1132 else { 1133 int n = hpos - output_hpos; 1134 if (vpos == output_vpos 1135 && (!gcol || gcol == current_glyph_color) 1136 && (!fcol || fcol == current_fill_color) 1137 && n > 0 && n < 100) { 1138 put(char(n/10 + '0')); 1139 put(char(n%10 + '0')); 1140 put(c); 1141 output_hpos = hpos; 1142 } 1143 else { 1144 glyph_color(gcol); 1145 fill_color(fcol); 1146 flush_tbuf(); 1147 do_motion(); 1148 put('c'); 1149 put(c); 1150 } 1151 } 1152 } 1153 1154 // set_font calls `flush_tbuf' if necessary. 1155 1156 void troff_output_file::set_font(tfont *tf) 1157 { 1158 if (current_tfont == tf) 1159 return; 1160 flush_tbuf(); 1161 int n = tf->get_input_position(); 1162 symbol nm = tf->get_name(); 1163 if (n >= nfont_positions || font_position[n] != nm) { 1164 put("x font "); 1165 put(n); 1166 put(' '); 1167 put(nm.contents()); 1168 put('\n'); 1169 if (n >= nfont_positions) { 1170 int old_nfont_positions = nfont_positions; 1171 symbol *old_font_position = font_position; 1172 nfont_positions *= 3; 1173 nfont_positions /= 2; 1174 if (nfont_positions <= n) 1175 nfont_positions = n + 10; 1176 font_position = new symbol[nfont_positions]; 1177 memcpy(font_position, old_font_position, 1178 old_nfont_positions*sizeof(symbol)); 1179 a_delete old_font_position; 1180 } 1181 font_position[n] = nm; 1182 } 1183 if (current_font_number != n) { 1184 put('f'); 1185 put(n); 1186 put('\n'); 1187 current_font_number = n; 1188 } 1189 int size = tf->get_size().to_scaled_points(); 1190 if (current_size != size) { 1191 put('s'); 1192 put(size); 1193 put('\n'); 1194 current_size = size; 1195 } 1196 int slant = tf->get_slant(); 1197 if (current_slant != slant) { 1198 put("x Slant "); 1199 put(slant); 1200 put('\n'); 1201 current_slant = slant; 1202 } 1203 int height = tf->get_height(); 1204 if (current_height != height) { 1205 put("x Height "); 1206 put(height == 0 ? current_size : height); 1207 put('\n'); 1208 current_height = height; 1209 } 1210 current_tfont = tf; 1211 } 1212 1213 // fill_color calls `flush_tbuf' and `do_motion' if necessary. 1214 1215 void troff_output_file::fill_color(color *col) 1216 { 1217 if (!col || current_fill_color == col) 1218 return; 1219 current_fill_color = col; 1220 if (!color_flag) 1221 return; 1222 flush_tbuf(); 1223 do_motion(); 1224 put("DF"); 1225 unsigned int components[4]; 1226 color_scheme cs; 1227 cs = col->get_components(components); 1228 switch (cs) { 1229 case DEFAULT: 1230 put('d'); 1231 break; 1232 case RGB: 1233 put("r "); 1234 put(Red); 1235 put(' '); 1236 put(Green); 1237 put(' '); 1238 put(Blue); 1239 break; 1240 case CMY: 1241 put("c "); 1242 put(Cyan); 1243 put(' '); 1244 put(Magenta); 1245 put(' '); 1246 put(Yellow); 1247 break; 1248 case CMYK: 1249 put("k "); 1250 put(Cyan); 1251 put(' '); 1252 put(Magenta); 1253 put(' '); 1254 put(Yellow); 1255 put(' '); 1256 put(Black); 1257 break; 1258 case GRAY: 1259 put("g "); 1260 put(Gray); 1261 break; 1262 } 1263 put('\n'); 1264 } 1265 1266 // glyph_color calls `flush_tbuf' and `do_motion' if necessary. 1267 1268 void troff_output_file::glyph_color(color *col) 1269 { 1270 if (!col || current_glyph_color == col) 1271 return; 1272 current_glyph_color = col; 1273 if (!color_flag) 1274 return; 1275 flush_tbuf(); 1276 // grotty doesn't like a color command if the vertical position is zero. 1277 do_motion(); 1278 put("m"); 1279 unsigned int components[4]; 1280 color_scheme cs; 1281 cs = col->get_components(components); 1282 switch (cs) { 1283 case DEFAULT: 1284 put('d'); 1285 break; 1286 case RGB: 1287 put("r "); 1288 put(Red); 1289 put(' '); 1290 put(Green); 1291 put(' '); 1292 put(Blue); 1293 break; 1294 case CMY: 1295 put("c "); 1296 put(Cyan); 1297 put(' '); 1298 put(Magenta); 1299 put(' '); 1300 put(Yellow); 1301 break; 1302 case CMYK: 1303 put("k "); 1304 put(Cyan); 1305 put(' '); 1306 put(Magenta); 1307 put(' '); 1308 put(Yellow); 1309 put(' '); 1310 put(Black); 1311 break; 1312 case GRAY: 1313 put("g "); 1314 put(Gray); 1315 break; 1316 } 1317 put('\n'); 1318 } 1319 1320 void troff_output_file::add_to_tag_list(string s) 1321 { 1322 if (tag_list == string("")) 1323 tag_list = s; 1324 else { 1325 tag_list += string("\n"); 1326 tag_list += s; 1327 } 1328 } 1329 1330 // determine_line_limits - works out the smallest box which will contain 1331 // the entity, code, built from the point array. 1332 void troff_output_file::determine_line_limits(char code, hvpair *point, 1333 int npoints) 1334 { 1335 int i, x, y; 1336 1337 if (!is_on()) 1338 return; 1339 1340 switch (code) { 1341 case 'c': 1342 case 'C': 1343 // only the h field is used when defining a circle 1344 check_output_limits(output_hpos, 1345 output_vpos - point[0].h.to_units()/2); 1346 check_output_limits(output_hpos + point[0].h.to_units(), 1347 output_vpos + point[0].h.to_units()/2); 1348 break; 1349 case 'E': 1350 case 'e': 1351 check_output_limits(output_hpos, 1352 output_vpos - point[0].v.to_units()/2); 1353 check_output_limits(output_hpos + point[0].h.to_units(), 1354 output_vpos + point[0].v.to_units()/2); 1355 break; 1356 case 'P': 1357 case 'p': 1358 x = output_hpos; 1359 y = output_vpos; 1360 check_output_limits(x, y); 1361 for (i = 0; i < npoints; i++) { 1362 x += point[i].h.to_units(); 1363 y += point[i].v.to_units(); 1364 check_output_limits(x, y); 1365 } 1366 break; 1367 case 't': 1368 x = output_hpos; 1369 y = output_vpos; 1370 for (i = 0; i < npoints; i++) { 1371 x += point[i].h.to_units(); 1372 y += point[i].v.to_units(); 1373 check_output_limits(x, y); 1374 } 1375 break; 1376 case 'a': 1377 double c[2]; 1378 int p[4]; 1379 int minx, miny, maxx, maxy; 1380 x = output_hpos; 1381 y = output_vpos; 1382 p[0] = point[0].h.to_units(); 1383 p[1] = point[0].v.to_units(); 1384 p[2] = point[1].h.to_units(); 1385 p[3] = point[1].v.to_units(); 1386 if (adjust_arc_center(p, c)) { 1387 check_output_arc_limits(x, y, 1388 p[0], p[1], p[2], p[3], 1389 c[0], c[1], 1390 &minx, &maxx, &miny, &maxy); 1391 check_output_limits(minx, miny); 1392 check_output_limits(maxx, maxy); 1393 break; 1394 } 1395 // fall through 1396 case 'l': 1397 x = output_hpos; 1398 y = output_vpos; 1399 check_output_limits(x, y); 1400 for (i = 0; i < npoints; i++) { 1401 x += point[i].h.to_units(); 1402 y += point[i].v.to_units(); 1403 check_output_limits(x, y); 1404 } 1405 break; 1406 default: 1407 x = output_hpos; 1408 y = output_vpos; 1409 for (i = 0; i < npoints; i++) { 1410 x += point[i].h.to_units(); 1411 y += point[i].v.to_units(); 1412 check_output_limits(x, y); 1413 } 1414 } 1415 } 1416 1417 void troff_output_file::draw(char code, hvpair *point, int npoints, 1418 font_size fsize, color *gcol, color *fcol) 1419 { 1420 int i; 1421 glyph_color(gcol); 1422 fill_color(fcol); 1423 flush_tbuf(); 1424 do_motion(); 1425 if (is_on()) { 1426 int size = fsize.to_scaled_points(); 1427 if (current_size != size) { 1428 put('s'); 1429 put(size); 1430 put('\n'); 1431 current_size = size; 1432 current_tfont = 0; 1433 } 1434 put('D'); 1435 put(code); 1436 if (code == 'c') { 1437 put(' '); 1438 put(point[0].h.to_units()); 1439 } 1440 else 1441 for (i = 0; i < npoints; i++) { 1442 put(' '); 1443 put(point[i].h.to_units()); 1444 put(' '); 1445 put(point[i].v.to_units()); 1446 } 1447 determine_line_limits(code, point, npoints); 1448 } 1449 1450 for (i = 0; i < npoints; i++) 1451 output_hpos += point[i].h.to_units(); 1452 hpos = output_hpos; 1453 if (code != 'e') { 1454 for (i = 0; i < npoints; i++) 1455 output_vpos += point[i].v.to_units(); 1456 vpos = output_vpos; 1457 } 1458 if (is_on()) 1459 put('\n'); 1460 } 1461 1462 void troff_output_file::really_on() 1463 { 1464 flush_tbuf(); 1465 force_motion = 1; 1466 do_motion(); 1467 } 1468 1469 void troff_output_file::really_off() 1470 { 1471 flush_tbuf(); 1472 } 1473 1474 void troff_output_file::really_put_filename(const char *filename) 1475 { 1476 flush_tbuf(); 1477 put("F "); 1478 put(filename); 1479 put('\n'); 1480 } 1481 1482 void troff_output_file::really_begin_page(int pageno, vunits page_length) 1483 { 1484 flush_tbuf(); 1485 if (begun_page) { 1486 if (page_length > V0) { 1487 put('V'); 1488 put(page_length.to_units()); 1489 put('\n'); 1490 } 1491 } 1492 else 1493 begun_page = 1; 1494 current_tfont = 0; 1495 current_font_number = -1; 1496 current_size = 0; 1497 // current_height = 0; 1498 // current_slant = 0; 1499 hpos = 0; 1500 vpos = 0; 1501 output_hpos = 0; 1502 output_vpos = 0; 1503 force_motion = 1; 1504 for (int i = 0; i < nfont_positions; i++) 1505 font_position[i] = NULL_SYMBOL; 1506 put('p'); 1507 put(pageno); 1508 put('\n'); 1509 } 1510 1511 void troff_output_file::really_copy_file(hunits x, vunits y, 1512 const char *filename) 1513 { 1514 moveto(x, y); 1515 flush_tbuf(); 1516 do_motion(); 1517 errno = 0; 1518 FILE *ifp = include_search_path.open_file_cautious(filename); 1519 if (ifp == 0) 1520 error("can't open `%1': %2", filename, strerror(errno)); 1521 else { 1522 int c; 1523 while ((c = getc(ifp)) != EOF) 1524 put(char(c)); 1525 fclose(ifp); 1526 } 1527 force_motion = 1; 1528 current_size = 0; 1529 current_tfont = 0; 1530 current_font_number = -1; 1531 for (int i = 0; i < nfont_positions; i++) 1532 font_position[i] = NULL_SYMBOL; 1533 } 1534 1535 void troff_output_file::really_transparent_char(unsigned char c) 1536 { 1537 put(c); 1538 } 1539 1540 troff_output_file::~troff_output_file() 1541 { 1542 a_delete font_position; 1543 } 1544 1545 void troff_output_file::trailer(vunits page_length) 1546 { 1547 flush_tbuf(); 1548 if (page_length > V0) { 1549 put("x trailer\n"); 1550 put('V'); 1551 put(page_length.to_units()); 1552 put('\n'); 1553 } 1554 put("x stop\n"); 1555 } 1556 1557 troff_output_file::troff_output_file() 1558 : current_slant(0), current_height(0), current_fill_color(0), 1559 current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0), 1560 cur_div_level(0) 1561 { 1562 font_position = new symbol[nfont_positions]; 1563 put("x T "); 1564 put(device); 1565 put('\n'); 1566 put("x res "); 1567 put(units_per_inch); 1568 put(' '); 1569 put(hresolution); 1570 put(' '); 1571 put(vresolution); 1572 put('\n'); 1573 put("x init\n"); 1574 } 1575 1576 /* output_file */ 1577 1578 output_file *the_output = 0; 1579 1580 output_file::output_file() 1581 { 1582 } 1583 1584 output_file::~output_file() 1585 { 1586 } 1587 1588 void output_file::trailer(vunits) 1589 { 1590 } 1591 1592 void output_file::put_filename(const char *) 1593 { 1594 } 1595 1596 void output_file::on() 1597 { 1598 } 1599 1600 void output_file::off() 1601 { 1602 } 1603 1604 real_output_file::real_output_file() 1605 : printing(0), output_on(1) 1606 { 1607 #ifndef POPEN_MISSING 1608 if (pipe_command) { 1609 if ((fp = popen(pipe_command, POPEN_WT)) != 0) { 1610 piped = 1; 1611 return; 1612 } 1613 error("pipe open failed: %1", strerror(errno)); 1614 } 1615 piped = 0; 1616 #endif /* not POPEN_MISSING */ 1617 fp = stdout; 1618 } 1619 1620 real_output_file::~real_output_file() 1621 { 1622 if (!fp) 1623 return; 1624 // To avoid looping, set fp to 0 before calling fatal(). 1625 if (ferror(fp) || fflush(fp) < 0) { 1626 fp = 0; 1627 fatal("error writing output file"); 1628 } 1629 #ifndef POPEN_MISSING 1630 if (piped) { 1631 int result = pclose(fp); 1632 fp = 0; 1633 if (result < 0) 1634 fatal("pclose failed"); 1635 if (!WIFEXITED(result)) 1636 error("output process `%1' got fatal signal %2", 1637 pipe_command, 1638 WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result)); 1639 else { 1640 int exit_status = WEXITSTATUS(result); 1641 if (exit_status != 0) 1642 error("output process `%1' exited with status %2", 1643 pipe_command, exit_status); 1644 } 1645 } 1646 else 1647 #endif /* not POPEN MISSING */ 1648 if (fclose(fp) < 0) { 1649 fp = 0; 1650 fatal("error closing output file"); 1651 } 1652 } 1653 1654 void real_output_file::flush() 1655 { 1656 if (fflush(fp) < 0) 1657 fatal("error writing output file"); 1658 } 1659 1660 int real_output_file::is_printing() 1661 { 1662 return printing; 1663 } 1664 1665 void real_output_file::begin_page(int pageno, vunits page_length) 1666 { 1667 printing = in_output_page_list(pageno); 1668 if (printing) 1669 really_begin_page(pageno, page_length); 1670 } 1671 1672 void real_output_file::copy_file(hunits x, vunits y, const char *filename) 1673 { 1674 if (printing && output_on) 1675 really_copy_file(x, y, filename); 1676 check_output_limits(x.to_units(), y.to_units()); 1677 } 1678 1679 void real_output_file::transparent_char(unsigned char c) 1680 { 1681 if (printing && output_on) 1682 really_transparent_char(c); 1683 } 1684 1685 void real_output_file::print_line(hunits x, vunits y, node *n, 1686 vunits before, vunits after, hunits width) 1687 { 1688 if (printing) 1689 really_print_line(x, y, n, before, after, width); 1690 delete_node_list(n); 1691 } 1692 1693 void real_output_file::really_copy_file(hunits, vunits, const char *) 1694 { 1695 // do nothing 1696 } 1697 1698 void real_output_file::put_filename(const char *filename) 1699 { 1700 really_put_filename(filename); 1701 } 1702 1703 void real_output_file::really_put_filename(const char *) 1704 { 1705 } 1706 1707 void real_output_file::on() 1708 { 1709 really_on(); 1710 if (output_on == 0) 1711 output_on = 1; 1712 } 1713 1714 void real_output_file::off() 1715 { 1716 really_off(); 1717 output_on = 0; 1718 } 1719 1720 int real_output_file::is_on() 1721 { 1722 return output_on; 1723 } 1724 1725 void real_output_file::really_on() 1726 { 1727 } 1728 1729 void real_output_file::really_off() 1730 { 1731 } 1732 1733 /* ascii_output_file */ 1734 1735 void ascii_output_file::really_transparent_char(unsigned char c) 1736 { 1737 putc(c, fp); 1738 } 1739 1740 void ascii_output_file::really_print_line(hunits, vunits, node *n, 1741 vunits, vunits, hunits) 1742 { 1743 while (n != 0) { 1744 n->ascii_print(this); 1745 n = n->next; 1746 } 1747 fputc('\n', fp); 1748 } 1749 1750 void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/) 1751 { 1752 fputs("<beginning of page>\n", fp); 1753 } 1754 1755 ascii_output_file::ascii_output_file() 1756 { 1757 } 1758 1759 /* suppress_output_file */ 1760 1761 suppress_output_file::suppress_output_file() 1762 { 1763 } 1764 1765 void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits) 1766 { 1767 } 1768 1769 void suppress_output_file::really_begin_page(int, vunits) 1770 { 1771 } 1772 1773 void suppress_output_file::really_transparent_char(unsigned char) 1774 { 1775 } 1776 1777 /* glyphs, ligatures, kerns, discretionary breaks */ 1778 1779 class charinfo_node : public node { 1780 protected: 1781 charinfo *ci; 1782 public: 1783 charinfo_node(charinfo *, statem *, int, node * = 0); 1784 int ends_sentence(); 1785 int overlaps_vertically(); 1786 int overlaps_horizontally(); 1787 }; 1788 1789 charinfo_node::charinfo_node(charinfo *c, statem *s, int pop, node *x) 1790 : node(x, s, pop), ci(c) 1791 { 1792 } 1793 1794 int charinfo_node::ends_sentence() 1795 { 1796 if (ci->ends_sentence()) 1797 return 1; 1798 else if (ci->transparent()) 1799 return 2; 1800 else 1801 return 0; 1802 } 1803 1804 int charinfo_node::overlaps_horizontally() 1805 { 1806 return ci->overlaps_horizontally(); 1807 } 1808 1809 int charinfo_node::overlaps_vertically() 1810 { 1811 return ci->overlaps_vertically(); 1812 } 1813 1814 class glyph_node : public charinfo_node { 1815 static glyph_node *free_list; 1816 protected: 1817 tfont *tf; 1818 color *gcol; 1819 color *fcol; /* this is needed for grotty */ 1820 #ifdef STORE_WIDTH 1821 hunits wid; 1822 glyph_node(charinfo *, tfont *, color *, color *, hunits, 1823 statem *, int, node * = 0); 1824 #endif 1825 public: 1826 void *operator new(size_t); 1827 void operator delete(void *); 1828 glyph_node(charinfo *, tfont *, color *, color *, 1829 statem *, int, node * = 0); 1830 ~glyph_node() {} 1831 node *copy(); 1832 node *merge_glyph_node(glyph_node *); 1833 node *merge_self(node *); 1834 hunits width(); 1835 node *last_char_node(); 1836 units size(); 1837 void vertical_extent(vunits *, vunits *); 1838 hunits subscript_correction(); 1839 hunits italic_correction(); 1840 hunits left_italic_correction(); 1841 hunits skew(); 1842 hyphenation_type get_hyphenation_type(); 1843 tfont *get_tfont(); 1844 color *get_glyph_color(); 1845 color *get_fill_color(); 1846 void tprint(troff_output_file *); 1847 void zero_width_tprint(troff_output_file *); 1848 hyphen_list *get_hyphen_list(hyphen_list *, int *); 1849 node *add_self(node *, hyphen_list **); 1850 void ascii_print(ascii_output_file *); 1851 void asciify(macro *); 1852 int character_type(); 1853 int same(node *); 1854 const char *type(); 1855 int force_tprint(); 1856 int is_tag(); 1857 void debug_node(); 1858 }; 1859 1860 glyph_node *glyph_node::free_list = 0; 1861 1862 class ligature_node : public glyph_node { 1863 node *n1; 1864 node *n2; 1865 #ifdef STORE_WIDTH 1866 ligature_node(charinfo *, tfont *, color *, color *, hunits, 1867 node *, node *, statem *, int, node * = 0); 1868 #endif 1869 public: 1870 void *operator new(size_t); 1871 void operator delete(void *); 1872 ligature_node(charinfo *, tfont *, color *, color *, 1873 node *, node *, statem *, int, node * = 0); 1874 ~ligature_node(); 1875 node *copy(); 1876 node *add_self(node *, hyphen_list **); 1877 hyphen_list *get_hyphen_list(hyphen_list *, int *); 1878 void ascii_print(ascii_output_file *); 1879 void asciify(macro *); 1880 int same(node *); 1881 const char *type(); 1882 int force_tprint(); 1883 int is_tag(); 1884 }; 1885 1886 class kern_pair_node : public node { 1887 hunits amount; 1888 node *n1; 1889 node *n2; 1890 public: 1891 kern_pair_node(hunits, node *, node *, statem *, int, node * = 0); 1892 ~kern_pair_node(); 1893 node *copy(); 1894 node *merge_glyph_node(glyph_node *); 1895 node *add_self(node *, hyphen_list **); 1896 hyphen_list *get_hyphen_list(hyphen_list *, int *); 1897 node *add_discretionary_hyphen(); 1898 hunits width(); 1899 node *last_char_node(); 1900 hunits italic_correction(); 1901 hunits subscript_correction(); 1902 void tprint(troff_output_file *); 1903 hyphenation_type get_hyphenation_type(); 1904 int ends_sentence(); 1905 void ascii_print(ascii_output_file *); 1906 void asciify(macro *); 1907 int same(node *); 1908 const char *type(); 1909 int force_tprint(); 1910 int is_tag(); 1911 void vertical_extent(vunits *, vunits *); 1912 }; 1913 1914 class dbreak_node : public node { 1915 node *none; 1916 node *pre; 1917 node *post; 1918 public: 1919 dbreak_node(node *, node *, statem *, int, node * = 0); 1920 ~dbreak_node(); 1921 node *copy(); 1922 node *merge_glyph_node(glyph_node *); 1923 node *add_discretionary_hyphen(); 1924 hunits width(); 1925 node *last_char_node(); 1926 hunits italic_correction(); 1927 hunits subscript_correction(); 1928 void tprint(troff_output_file *); 1929 breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0, 1930 int is_inner = 0); 1931 int nbreaks(); 1932 int ends_sentence(); 1933 void split(int, node **, node **); 1934 hyphenation_type get_hyphenation_type(); 1935 void ascii_print(ascii_output_file *); 1936 void asciify(macro *); 1937 int same(node *); 1938 const char *type(); 1939 int force_tprint(); 1940 int is_tag(); 1941 }; 1942 1943 void *glyph_node::operator new(size_t n) 1944 { 1945 assert(n == sizeof(glyph_node)); 1946 if (!free_list) { 1947 const int BLOCK = 1024; 1948 free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK]; 1949 for (int i = 0; i < BLOCK - 1; i++) 1950 free_list[i].next = free_list + i + 1; 1951 free_list[BLOCK-1].next = 0; 1952 } 1953 glyph_node *p = free_list; 1954 free_list = (glyph_node *)(free_list->next); 1955 p->next = 0; 1956 return p; 1957 } 1958 1959 void *ligature_node::operator new(size_t n) 1960 { 1961 return new char[n]; 1962 } 1963 1964 void glyph_node::operator delete(void *p) 1965 { 1966 if (p) { 1967 ((glyph_node *)p)->next = free_list; 1968 free_list = (glyph_node *)p; 1969 } 1970 } 1971 1972 void ligature_node::operator delete(void *p) 1973 { 1974 delete[] (char *)p; 1975 } 1976 1977 glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc, 1978 statem *s, int pop, node *x) 1979 : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc) 1980 { 1981 #ifdef STORE_WIDTH 1982 wid = tf->get_width(ci); 1983 #endif 1984 } 1985 1986 #ifdef STORE_WIDTH 1987 glyph_node::glyph_node(charinfo *c, tfont *t, 1988 color *gc, color *fc, hunits w, 1989 statem *s, int pop, node *x) 1990 : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc), wid(w) 1991 { 1992 } 1993 #endif 1994 1995 node *glyph_node::copy() 1996 { 1997 #ifdef STORE_WIDTH 1998 return new glyph_node(ci, tf, gcol, fcol, wid, state, div_nest_level); 1999 #else 2000 return new glyph_node(ci, tf, gcol, fcol, state, div_nest_level); 2001 #endif 2002 } 2003 2004 node *glyph_node::merge_self(node *nd) 2005 { 2006 return nd->merge_glyph_node(this); 2007 } 2008 2009 int glyph_node::character_type() 2010 { 2011 return tf->get_character_type(ci); 2012 } 2013 2014 node *glyph_node::add_self(node *n, hyphen_list **p) 2015 { 2016 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); 2017 next = 0; 2018 node *nn; 2019 if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) { 2020 next = n; 2021 nn = this; 2022 } 2023 if ((*p)->hyphen) 2024 nn = nn->add_discretionary_hyphen(); 2025 hyphen_list *pp = *p; 2026 *p = (*p)->next; 2027 delete pp; 2028 return nn; 2029 } 2030 2031 units glyph_node::size() 2032 { 2033 return tf->get_size().to_units(); 2034 } 2035 2036 hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail, int *count) 2037 { 2038 (*count)++; 2039 return new hyphen_list(ci->get_hyphenation_code(), tail); 2040 } 2041 2042 tfont *node::get_tfont() 2043 { 2044 return 0; 2045 } 2046 2047 tfont *glyph_node::get_tfont() 2048 { 2049 return tf; 2050 } 2051 2052 color *node::get_glyph_color() 2053 { 2054 return 0; 2055 } 2056 2057 color *glyph_node::get_glyph_color() 2058 { 2059 return gcol; 2060 } 2061 2062 color *node::get_fill_color() 2063 { 2064 return 0; 2065 } 2066 2067 color *glyph_node::get_fill_color() 2068 { 2069 return fcol; 2070 } 2071 2072 node *node::merge_glyph_node(glyph_node *) 2073 { 2074 return 0; 2075 } 2076 2077 node *glyph_node::merge_glyph_node(glyph_node *gn) 2078 { 2079 if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) { 2080 charinfo *lig; 2081 if ((lig = tf->get_lig(ci, gn->ci)) != 0) { 2082 node *next1 = next; 2083 next = 0; 2084 return new ligature_node(lig, tf, gcol, fcol, this, gn, state, 2085 gn->div_nest_level, next1); 2086 } 2087 hunits kern; 2088 if (tf->get_kern(ci, gn->ci, &kern)) { 2089 node *next1 = next; 2090 next = 0; 2091 return new kern_pair_node(kern, this, gn, state, 2092 gn->div_nest_level, next1); 2093 } 2094 } 2095 return 0; 2096 } 2097 2098 #ifdef STORE_WIDTH 2099 inline 2100 #endif 2101 hunits glyph_node::width() 2102 { 2103 #ifdef STORE_WIDTH 2104 return wid; 2105 #else 2106 return tf->get_width(ci); 2107 #endif 2108 } 2109 2110 node *glyph_node::last_char_node() 2111 { 2112 return this; 2113 } 2114 2115 void glyph_node::vertical_extent(vunits *min, vunits *max) 2116 { 2117 *min = -tf->get_char_height(ci); 2118 *max = tf->get_char_depth(ci); 2119 } 2120 2121 hunits glyph_node::skew() 2122 { 2123 return tf->get_char_skew(ci); 2124 } 2125 2126 hunits glyph_node::subscript_correction() 2127 { 2128 return tf->get_subscript_correction(ci); 2129 } 2130 2131 hunits glyph_node::italic_correction() 2132 { 2133 return tf->get_italic_correction(ci); 2134 } 2135 2136 hunits glyph_node::left_italic_correction() 2137 { 2138 return tf->get_left_italic_correction(ci); 2139 } 2140 2141 hyphenation_type glyph_node::get_hyphenation_type() 2142 { 2143 return HYPHEN_MIDDLE; 2144 } 2145 2146 void glyph_node::ascii_print(ascii_output_file *ascii) 2147 { 2148 unsigned char c = ci->get_ascii_code(); 2149 if (c != 0) 2150 ascii->outc(c); 2151 else 2152 ascii->outs(ci->nm.contents()); 2153 } 2154 2155 void glyph_node::debug_node() 2156 { 2157 unsigned char c = ci->get_ascii_code(); 2158 fprintf(stderr, "{ %s [", type()); 2159 if (c) 2160 fprintf(stderr, "%c", c); 2161 else 2162 fprintf(stderr, "%s", ci->nm.contents()); 2163 if (push_state) 2164 fprintf(stderr, " <push_state>"); 2165 if (state) 2166 state->display_state(); 2167 fprintf(stderr, " nest level %d", div_nest_level); 2168 fprintf(stderr, "]}\n"); 2169 fflush(stderr); 2170 } 2171 2172 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc, 2173 node *gn1, node *gn2, statem *s, 2174 int pop, node *x) 2175 : glyph_node(c, t, gc, fc, s, pop, x), n1(gn1), n2(gn2) 2176 { 2177 } 2178 2179 #ifdef STORE_WIDTH 2180 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc, 2181 hunits w, node *gn1, node *gn2, statem *s, 2182 int pop, node *x) 2183 : glyph_node(c, t, gc, fc, w, s, pop, x), n1(gn1), n2(gn2) 2184 { 2185 } 2186 #endif 2187 2188 ligature_node::~ligature_node() 2189 { 2190 delete n1; 2191 delete n2; 2192 } 2193 2194 node *ligature_node::copy() 2195 { 2196 #ifdef STORE_WIDTH 2197 return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy(), 2198 state, div_nest_level); 2199 #else 2200 return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy(), 2201 state, div_nest_level); 2202 #endif 2203 } 2204 2205 void ligature_node::ascii_print(ascii_output_file *ascii) 2206 { 2207 n1->ascii_print(ascii); 2208 n2->ascii_print(ascii); 2209 } 2210 2211 hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail, int *count) 2212 { 2213 hyphen_list *hl = n2->get_hyphen_list(tail, count); 2214 return n1->get_hyphen_list(hl, count); 2215 } 2216 2217 node *ligature_node::add_self(node *n, hyphen_list **p) 2218 { 2219 n = n1->add_self(n, p); 2220 n = n2->add_self(n, p); 2221 n1 = n2 = 0; 2222 delete this; 2223 return n; 2224 } 2225 2226 kern_pair_node::kern_pair_node(hunits n, node *first, node *second, 2227 statem* s, int pop, node *x) 2228 : node(x, s, pop), amount(n), n1(first), n2(second) 2229 { 2230 } 2231 2232 dbreak_node::dbreak_node(node *n, node *p, statem *s, int pop, node *x) 2233 : node(x, s, pop), none(n), pre(p), post(0) 2234 { 2235 } 2236 2237 node *dbreak_node::merge_glyph_node(glyph_node *gn) 2238 { 2239 glyph_node *gn2 = (glyph_node *)gn->copy(); 2240 node *new_none = none ? none->merge_glyph_node(gn) : 0; 2241 node *new_post = post ? post->merge_glyph_node(gn2) : 0; 2242 if (new_none == 0 && new_post == 0) { 2243 delete gn2; 2244 return 0; 2245 } 2246 if (new_none != 0) 2247 none = new_none; 2248 else { 2249 gn->next = none; 2250 none = gn; 2251 } 2252 if (new_post != 0) 2253 post = new_post; 2254 else { 2255 gn2->next = post; 2256 post = gn2; 2257 } 2258 return this; 2259 } 2260 2261 node *kern_pair_node::merge_glyph_node(glyph_node *gn) 2262 { 2263 node *nd = n2->merge_glyph_node(gn); 2264 if (nd == 0) 2265 return 0; 2266 n2 = nd; 2267 nd = n2->merge_self(n1); 2268 if (nd) { 2269 nd->next = next; 2270 n1 = 0; 2271 n2 = 0; 2272 delete this; 2273 return nd; 2274 } 2275 return this; 2276 } 2277 2278 hunits kern_pair_node::italic_correction() 2279 { 2280 return n2->italic_correction(); 2281 } 2282 2283 hunits kern_pair_node::subscript_correction() 2284 { 2285 return n2->subscript_correction(); 2286 } 2287 2288 void kern_pair_node::vertical_extent(vunits *min, vunits *max) 2289 { 2290 n1->vertical_extent(min, max); 2291 vunits min2, max2; 2292 n2->vertical_extent(&min2, &max2); 2293 if (min2 < *min) 2294 *min = min2; 2295 if (max2 > *max) 2296 *max = max2; 2297 } 2298 2299 node *kern_pair_node::add_discretionary_hyphen() 2300 { 2301 tfont *tf = n2->get_tfont(); 2302 if (tf) { 2303 if (tf->contains(soft_hyphen_char)) { 2304 color *gcol = n2->get_glyph_color(); 2305 color *fcol = n2->get_fill_color(); 2306 node *next1 = next; 2307 next = 0; 2308 node *n = copy(); 2309 glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol, 2310 state, div_nest_level); 2311 node *nn = n->merge_glyph_node(gn); 2312 if (nn == 0) { 2313 gn->next = n; 2314 nn = gn; 2315 } 2316 return new dbreak_node(this, nn, state, div_nest_level, next1); 2317 } 2318 } 2319 return this; 2320 } 2321 2322 kern_pair_node::~kern_pair_node() 2323 { 2324 if (n1 != 0) 2325 delete n1; 2326 if (n2 != 0) 2327 delete n2; 2328 } 2329 2330 dbreak_node::~dbreak_node() 2331 { 2332 delete_node_list(pre); 2333 delete_node_list(post); 2334 delete_node_list(none); 2335 } 2336 2337 node *kern_pair_node::copy() 2338 { 2339 return new kern_pair_node(amount, n1->copy(), n2->copy(), state, 2340 div_nest_level); 2341 } 2342 2343 node *copy_node_list(node *n) 2344 { 2345 node *p = 0; 2346 while (n != 0) { 2347 node *nn = n->copy(); 2348 nn->next = p; 2349 p = nn; 2350 n = n->next; 2351 } 2352 while (p != 0) { 2353 node *pp = p->next; 2354 p->next = n; 2355 n = p; 2356 p = pp; 2357 } 2358 return n; 2359 } 2360 2361 void delete_node_list(node *n) 2362 { 2363 while (n != 0) { 2364 node *tem = n; 2365 n = n->next; 2366 delete tem; 2367 } 2368 } 2369 2370 node *dbreak_node::copy() 2371 { 2372 dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre), 2373 state, div_nest_level); 2374 p->post = copy_node_list(post); 2375 return p; 2376 } 2377 2378 hyphen_list *node::get_hyphen_list(hyphen_list *tail, int *) 2379 { 2380 return tail; 2381 } 2382 2383 hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail, int *count) 2384 { 2385 hyphen_list *hl = n2->get_hyphen_list(tail, count); 2386 return n1->get_hyphen_list(hl, count); 2387 } 2388 2389 class hyphen_inhibitor_node : public node { 2390 public: 2391 hyphen_inhibitor_node(node * = 0); 2392 node *copy(); 2393 int same(node *); 2394 const char *type(); 2395 int force_tprint(); 2396 int is_tag(); 2397 hyphenation_type get_hyphenation_type(); 2398 }; 2399 2400 hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd) 2401 { 2402 } 2403 2404 node *hyphen_inhibitor_node::copy() 2405 { 2406 return new hyphen_inhibitor_node; 2407 } 2408 2409 int hyphen_inhibitor_node::same(node *) 2410 { 2411 return 1; 2412 } 2413 2414 const char *hyphen_inhibitor_node::type() 2415 { 2416 return "hyphen_inhibitor_node"; 2417 } 2418 2419 int hyphen_inhibitor_node::force_tprint() 2420 { 2421 return 0; 2422 } 2423 2424 int hyphen_inhibitor_node::is_tag() 2425 { 2426 return 0; 2427 } 2428 2429 hyphenation_type hyphen_inhibitor_node::get_hyphenation_type() 2430 { 2431 return HYPHEN_INHIBIT; 2432 } 2433 2434 /* add_discretionary_hyphen methods */ 2435 2436 node *dbreak_node::add_discretionary_hyphen() 2437 { 2438 if (post) 2439 post = post->add_discretionary_hyphen(); 2440 if (none) 2441 none = none->add_discretionary_hyphen(); 2442 return this; 2443 } 2444 2445 node *node::add_discretionary_hyphen() 2446 { 2447 tfont *tf = get_tfont(); 2448 if (!tf) 2449 return new hyphen_inhibitor_node(this); 2450 if (tf->contains(soft_hyphen_char)) { 2451 color *gcol = get_glyph_color(); 2452 color *fcol = get_fill_color(); 2453 node *next1 = next; 2454 next = 0; 2455 node *n = copy(); 2456 glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol, 2457 state, div_nest_level); 2458 node *n1 = n->merge_glyph_node(gn); 2459 if (n1 == 0) { 2460 gn->next = n; 2461 n1 = gn; 2462 } 2463 return new dbreak_node(this, n1, state, div_nest_level, next1); 2464 } 2465 return this; 2466 } 2467 2468 node *node::merge_self(node *) 2469 { 2470 return 0; 2471 } 2472 2473 node *node::add_self(node *n, hyphen_list ** /*p*/) 2474 { 2475 next = n; 2476 return this; 2477 } 2478 2479 node *kern_pair_node::add_self(node *n, hyphen_list **p) 2480 { 2481 n = n1->add_self(n, p); 2482 n = n2->add_self(n, p); 2483 n1 = n2 = 0; 2484 delete this; 2485 return n; 2486 } 2487 2488 hunits node::width() 2489 { 2490 return H0; 2491 } 2492 2493 node *node::last_char_node() 2494 { 2495 return 0; 2496 } 2497 2498 int node::force_tprint() 2499 { 2500 return 0; 2501 } 2502 2503 int node::is_tag() 2504 { 2505 return 0; 2506 } 2507 2508 hunits hmotion_node::width() 2509 { 2510 return n; 2511 } 2512 2513 units node::size() 2514 { 2515 return points_to_units(10); 2516 } 2517 2518 void node::debug_node() 2519 { 2520 fprintf(stderr, "{ %s ", type()); 2521 if (push_state) 2522 fprintf(stderr, " <push_state>"); 2523 if (state) 2524 fprintf(stderr, " <state>"); 2525 fprintf(stderr, " nest level %d", div_nest_level); 2526 fprintf(stderr, " }\n"); 2527 fflush(stderr); 2528 } 2529 2530 void node::debug_node_list() 2531 { 2532 node *n = next; 2533 2534 debug_node(); 2535 while (n != 0) { 2536 n->debug_node(); 2537 n = n->next; 2538 } 2539 } 2540 2541 hunits kern_pair_node::width() 2542 { 2543 return n1->width() + n2->width() + amount; 2544 } 2545 2546 node *kern_pair_node::last_char_node() 2547 { 2548 node *nd = n2->last_char_node(); 2549 if (nd) 2550 return nd; 2551 return n1->last_char_node(); 2552 } 2553 2554 hunits dbreak_node::width() 2555 { 2556 hunits x = H0; 2557 for (node *n = none; n != 0; n = n->next) 2558 x += n->width(); 2559 return x; 2560 } 2561 2562 node *dbreak_node::last_char_node() 2563 { 2564 for (node *n = none; n; n = n->next) { 2565 node *last_node = n->last_char_node(); 2566 if (last_node) 2567 return last_node; 2568 } 2569 return 0; 2570 } 2571 2572 hunits dbreak_node::italic_correction() 2573 { 2574 return none ? none->italic_correction() : H0; 2575 } 2576 2577 hunits dbreak_node::subscript_correction() 2578 { 2579 return none ? none->subscript_correction() : H0; 2580 } 2581 2582 class italic_corrected_node : public node { 2583 node *n; 2584 hunits x; 2585 public: 2586 italic_corrected_node(node *, hunits, statem *, int, node * = 0); 2587 ~italic_corrected_node(); 2588 node *copy(); 2589 void ascii_print(ascii_output_file *); 2590 void asciify(macro *); 2591 hunits width(); 2592 node *last_char_node(); 2593 void vertical_extent(vunits *, vunits *); 2594 int ends_sentence(); 2595 int overlaps_horizontally(); 2596 int overlaps_vertically(); 2597 int same(node *); 2598 hyphenation_type get_hyphenation_type(); 2599 tfont *get_tfont(); 2600 hyphen_list *get_hyphen_list(hyphen_list *, int *); 2601 int character_type(); 2602 void tprint(troff_output_file *); 2603 hunits subscript_correction(); 2604 hunits skew(); 2605 node *add_self(node *, hyphen_list **); 2606 const char *type(); 2607 int force_tprint(); 2608 int is_tag(); 2609 }; 2610 2611 node *node::add_italic_correction(hunits *wd) 2612 { 2613 hunits ic = italic_correction(); 2614 if (ic.is_zero()) 2615 return this; 2616 else { 2617 node *next1 = next; 2618 next = 0; 2619 *wd += ic; 2620 return new italic_corrected_node(this, ic, state, div_nest_level, next1); 2621 } 2622 } 2623 2624 italic_corrected_node::italic_corrected_node(node *nn, hunits xx, statem *s, 2625 int pop, node *p) 2626 : node(p, s, pop), n(nn), x(xx) 2627 { 2628 assert(n != 0); 2629 } 2630 2631 italic_corrected_node::~italic_corrected_node() 2632 { 2633 delete n; 2634 } 2635 2636 node *italic_corrected_node::copy() 2637 { 2638 return new italic_corrected_node(n->copy(), x, state, div_nest_level); 2639 } 2640 2641 hunits italic_corrected_node::width() 2642 { 2643 return n->width() + x; 2644 } 2645 2646 void italic_corrected_node::vertical_extent(vunits *min, vunits *max) 2647 { 2648 n->vertical_extent(min, max); 2649 } 2650 2651 void italic_corrected_node::tprint(troff_output_file *out) 2652 { 2653 n->tprint(out); 2654 out->right(x); 2655 } 2656 2657 hunits italic_corrected_node::skew() 2658 { 2659 return n->skew() - x/2; 2660 } 2661 2662 hunits italic_corrected_node::subscript_correction() 2663 { 2664 return n->subscript_correction() - x; 2665 } 2666 2667 void italic_corrected_node::ascii_print(ascii_output_file *out) 2668 { 2669 n->ascii_print(out); 2670 } 2671 2672 int italic_corrected_node::ends_sentence() 2673 { 2674 return n->ends_sentence(); 2675 } 2676 2677 int italic_corrected_node::overlaps_horizontally() 2678 { 2679 return n->overlaps_horizontally(); 2680 } 2681 2682 int italic_corrected_node::overlaps_vertically() 2683 { 2684 return n->overlaps_vertically(); 2685 } 2686 2687 node *italic_corrected_node::last_char_node() 2688 { 2689 return n->last_char_node(); 2690 } 2691 2692 tfont *italic_corrected_node::get_tfont() 2693 { 2694 return n->get_tfont(); 2695 } 2696 2697 hyphenation_type italic_corrected_node::get_hyphenation_type() 2698 { 2699 return n->get_hyphenation_type(); 2700 } 2701 2702 node *italic_corrected_node::add_self(node *nd, hyphen_list **p) 2703 { 2704 nd = n->add_self(nd, p); 2705 hunits not_interested; 2706 nd = nd->add_italic_correction(¬_interested); 2707 n = 0; 2708 delete this; 2709 return nd; 2710 } 2711 2712 hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail, 2713 int *count) 2714 { 2715 return n->get_hyphen_list(tail, count); 2716 } 2717 2718 int italic_corrected_node::character_type() 2719 { 2720 return n->character_type(); 2721 } 2722 2723 class break_char_node : public node { 2724 node *ch; 2725 char break_code; 2726 color *col; 2727 public: 2728 break_char_node(node *, int, color *, node * = 0); 2729 break_char_node(node *, int, color *, statem *, int, node * = 0); 2730 ~break_char_node(); 2731 node *copy(); 2732 hunits width(); 2733 vunits vertical_width(); 2734 node *last_char_node(); 2735 int character_type(); 2736 int ends_sentence(); 2737 node *add_self(node *, hyphen_list **); 2738 hyphen_list *get_hyphen_list(hyphen_list *, int *); 2739 void tprint(troff_output_file *); 2740 void zero_width_tprint(troff_output_file *); 2741 void ascii_print(ascii_output_file *); 2742 void asciify(macro *); 2743 hyphenation_type get_hyphenation_type(); 2744 int overlaps_vertically(); 2745 int overlaps_horizontally(); 2746 units size(); 2747 tfont *get_tfont(); 2748 int same(node *); 2749 const char *type(); 2750 int force_tprint(); 2751 int is_tag(); 2752 }; 2753 2754 break_char_node::break_char_node(node *n, int bc, color *c, node *x) 2755 : node(x), ch(n), break_code(bc), col(c) 2756 { 2757 } 2758 2759 break_char_node::break_char_node(node *n, int bc, color *c, statem *s, 2760 int pop, node *x) 2761 : node(x, s, pop), ch(n), break_code(bc), col(c) 2762 { 2763 } 2764 2765 break_char_node::~break_char_node() 2766 { 2767 delete ch; 2768 } 2769 2770 node *break_char_node::copy() 2771 { 2772 return new break_char_node(ch->copy(), break_code, col, state, 2773 div_nest_level); 2774 } 2775 2776 hunits break_char_node::width() 2777 { 2778 return ch->width(); 2779 } 2780 2781 vunits break_char_node::vertical_width() 2782 { 2783 return ch->vertical_width(); 2784 } 2785 2786 node *break_char_node::last_char_node() 2787 { 2788 return ch->last_char_node(); 2789 } 2790 2791 int break_char_node::character_type() 2792 { 2793 return ch->character_type(); 2794 } 2795 2796 int break_char_node::ends_sentence() 2797 { 2798 return ch->ends_sentence(); 2799 } 2800 2801 node *break_char_node::add_self(node *n, hyphen_list **p) 2802 { 2803 assert((*p)->hyphenation_code == 0); 2804 if ((*p)->breakable && (break_code & 1)) { 2805 n = new space_node(H0, col, n); 2806 n->freeze_space(); 2807 } 2808 next = n; 2809 n = this; 2810 if ((*p)->breakable && (break_code & 2)) { 2811 n = new space_node(H0, col, n); 2812 n->freeze_space(); 2813 } 2814 hyphen_list *pp = *p; 2815 *p = (*p)->next; 2816 delete pp; 2817 return n; 2818 } 2819 2820 hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail, int *) 2821 { 2822 return new hyphen_list(0, tail); 2823 } 2824 2825 hyphenation_type break_char_node::get_hyphenation_type() 2826 { 2827 return HYPHEN_MIDDLE; 2828 } 2829 2830 void break_char_node::ascii_print(ascii_output_file *ascii) 2831 { 2832 ch->ascii_print(ascii); 2833 } 2834 2835 int break_char_node::overlaps_vertically() 2836 { 2837 return ch->overlaps_vertically(); 2838 } 2839 2840 int break_char_node::overlaps_horizontally() 2841 { 2842 return ch->overlaps_horizontally(); 2843 } 2844 2845 units break_char_node::size() 2846 { 2847 return ch->size(); 2848 } 2849 2850 tfont *break_char_node::get_tfont() 2851 { 2852 return ch->get_tfont(); 2853 } 2854 2855 node *extra_size_node::copy() 2856 { 2857 return new extra_size_node(n, state, div_nest_level); 2858 } 2859 2860 extra_size_node::extra_size_node(vunits i, statem *s, int pop) 2861 : node(0, s, pop), n(i) 2862 { 2863 } 2864 2865 extra_size_node::extra_size_node(vunits i) 2866 : n(i) 2867 { 2868 } 2869 2870 node *vertical_size_node::copy() 2871 { 2872 return new vertical_size_node(n, state, div_nest_level); 2873 } 2874 2875 vertical_size_node::vertical_size_node(vunits i, statem *s, int pop) 2876 : node(0, s, pop), n(i) 2877 { 2878 } 2879 2880 vertical_size_node::vertical_size_node(vunits i) 2881 : n(i) 2882 { 2883 } 2884 2885 node *hmotion_node::copy() 2886 { 2887 return new hmotion_node(n, was_tab, unformat, col, state, div_nest_level); 2888 } 2889 2890 node *space_char_hmotion_node::copy() 2891 { 2892 return new space_char_hmotion_node(n, col, state, div_nest_level); 2893 } 2894 2895 vmotion_node::vmotion_node(vunits i, color *c) 2896 : n(i), col(c) 2897 { 2898 } 2899 2900 vmotion_node::vmotion_node(vunits i, color *c, statem *s, int pop) 2901 : node(0, s, pop), n(i), col(c) 2902 { 2903 } 2904 2905 node *vmotion_node::copy() 2906 { 2907 return new vmotion_node(n, col, state, div_nest_level); 2908 } 2909 2910 node *dummy_node::copy() 2911 { 2912 return new dummy_node; 2913 } 2914 2915 node *transparent_dummy_node::copy() 2916 { 2917 return new transparent_dummy_node; 2918 } 2919 2920 hline_node::~hline_node() 2921 { 2922 if (n) 2923 delete n; 2924 } 2925 2926 hline_node::hline_node(hunits i, node *c, node *nxt) 2927 : node(nxt), x(i), n(c) 2928 { 2929 } 2930 2931 hline_node::hline_node(hunits i, node *c, statem *s, int pop, node *nxt) 2932 : node(nxt, s, pop), x(i), n(c) 2933 { 2934 } 2935 2936 node *hline_node::copy() 2937 { 2938 return new hline_node(x, n ? n->copy() : 0, state, div_nest_level); 2939 } 2940 2941 hunits hline_node::width() 2942 { 2943 return x < H0 ? H0 : x; 2944 } 2945 2946 vline_node::vline_node(vunits i, node *c, node *nxt) 2947 : node(nxt), x(i), n(c) 2948 { 2949 } 2950 2951 vline_node::vline_node(vunits i, node *c, statem *s, int pop, node *nxt) 2952 : node(nxt, s, pop), x(i), n(c) 2953 { 2954 } 2955 2956 vline_node::~vline_node() 2957 { 2958 if (n) 2959 delete n; 2960 } 2961 2962 node *vline_node::copy() 2963 { 2964 return new vline_node(x, n ? n->copy() : 0, state, div_nest_level); 2965 } 2966 2967 hunits vline_node::width() 2968 { 2969 return n == 0 ? H0 : n->width(); 2970 } 2971 2972 zero_width_node::zero_width_node(node *nd, statem *s, int pop) 2973 : node(0, s, pop), n(nd) 2974 { 2975 } 2976 2977 zero_width_node::zero_width_node(node *nd) 2978 : n(nd) 2979 { 2980 } 2981 2982 zero_width_node::~zero_width_node() 2983 { 2984 delete_node_list(n); 2985 } 2986 2987 node *zero_width_node::copy() 2988 { 2989 return new zero_width_node(copy_node_list(n), state, div_nest_level); 2990 } 2991 2992 int node_list_character_type(node *p) 2993 { 2994 int t = 0; 2995 for (; p; p = p->next) 2996 t |= p->character_type(); 2997 return t; 2998 } 2999 3000 int zero_width_node::character_type() 3001 { 3002 return node_list_character_type(n); 3003 } 3004 3005 void node_list_vertical_extent(node *p, vunits *min, vunits *max) 3006 { 3007 *min = V0; 3008 *max = V0; 3009 vunits cur_vpos = V0; 3010 vunits v1, v2; 3011 for (; p; p = p->next) { 3012 p->vertical_extent(&v1, &v2); 3013 v1 += cur_vpos; 3014 if (v1 < *min) 3015 *min = v1; 3016 v2 += cur_vpos; 3017 if (v2 > *max) 3018 *max = v2; 3019 cur_vpos += p->vertical_width(); 3020 } 3021 } 3022 3023 void zero_width_node::vertical_extent(vunits *min, vunits *max) 3024 { 3025 node_list_vertical_extent(n, min, max); 3026 } 3027 3028 overstrike_node::overstrike_node() 3029 : list(0), max_width(H0) 3030 { 3031 } 3032 3033 overstrike_node::overstrike_node(statem *s, int pop) 3034 : node(0, s, pop), list(0), max_width(H0) 3035 { 3036 } 3037 3038 overstrike_node::~overstrike_node() 3039 { 3040 delete_node_list(list); 3041 } 3042 3043 node *overstrike_node::copy() 3044 { 3045 overstrike_node *on = new overstrike_node(state, div_nest_level); 3046 for (node *tem = list; tem; tem = tem->next) 3047 on->overstrike(tem->copy()); 3048 return on; 3049 } 3050 3051 void overstrike_node::overstrike(node *n) 3052 { 3053 if (n == 0) 3054 return; 3055 hunits w = n->width(); 3056 if (w > max_width) 3057 max_width = w; 3058 node **p; 3059 for (p = &list; *p; p = &(*p)->next) 3060 ; 3061 n->next = 0; 3062 *p = n; 3063 } 3064 3065 hunits overstrike_node::width() 3066 { 3067 return max_width; 3068 } 3069 3070 bracket_node::bracket_node() 3071 : list(0), max_width(H0) 3072 { 3073 } 3074 3075 bracket_node::bracket_node(statem *s, int pop) 3076 : node(0, s, pop), list(0), max_width(H0) 3077 { 3078 } 3079 3080 bracket_node::~bracket_node() 3081 { 3082 delete_node_list(list); 3083 } 3084 3085 node *bracket_node::copy() 3086 { 3087 bracket_node *on = new bracket_node(state, div_nest_level); 3088 node *last_node = 0; 3089 node *tem; 3090 if (list) 3091 list->last = 0; 3092 for (tem = list; tem; tem = tem->next) { 3093 if (tem->next) 3094 tem->next->last = tem; 3095 last_node = tem; 3096 } 3097 for (tem = last_node; tem; tem = tem->last) 3098 on->bracket(tem->copy()); 3099 return on; 3100 } 3101 3102 void bracket_node::bracket(node *n) 3103 { 3104 if (n == 0) 3105 return; 3106 hunits w = n->width(); 3107 if (w > max_width) 3108 max_width = w; 3109 n->next = list; 3110 list = n; 3111 } 3112 3113 hunits bracket_node::width() 3114 { 3115 return max_width; 3116 } 3117 3118 int node::nspaces() 3119 { 3120 return 0; 3121 } 3122 3123 int node::merge_space(hunits, hunits, hunits) 3124 { 3125 return 0; 3126 } 3127 3128 #if 0 3129 space_node *space_node::free_list = 0; 3130 3131 void *space_node::operator new(size_t n) 3132 { 3133 assert(n == sizeof(space_node)); 3134 if (!free_list) { 3135 free_list = (space_node *)new char[sizeof(space_node)*BLOCK]; 3136 for (int i = 0; i < BLOCK - 1; i++) 3137 free_list[i].next = free_list + i + 1; 3138 free_list[BLOCK-1].next = 0; 3139 } 3140 space_node *p = free_list; 3141 free_list = (space_node *)(free_list->next); 3142 p->next = 0; 3143 return p; 3144 } 3145 3146 inline void space_node::operator delete(void *p) 3147 { 3148 if (p) { 3149 ((space_node *)p)->next = free_list; 3150 free_list = (space_node *)p; 3151 } 3152 } 3153 #endif 3154 3155 space_node::space_node(hunits nn, color *c, node *p) 3156 : node(p, 0, 0), n(nn), set(0), was_escape_colon(0), col(c) 3157 { 3158 } 3159 3160 space_node::space_node(hunits nn, color *c, statem *s, int pop, node *p) 3161 : node(p, s, pop), n(nn), set(0), was_escape_colon(0), col(c) 3162 { 3163 } 3164 3165 space_node::space_node(hunits nn, int s, int flag, color *c, statem *st, 3166 int pop, node *p) 3167 : node(p, st, pop), n(nn), set(s), was_escape_colon(flag), col(c) 3168 { 3169 } 3170 3171 #if 0 3172 space_node::~space_node() 3173 { 3174 } 3175 #endif 3176 3177 node *space_node::copy() 3178 { 3179 return new space_node(n, set, was_escape_colon, col, state, div_nest_level); 3180 } 3181 3182 int space_node::force_tprint() 3183 { 3184 return 0; 3185 } 3186 3187 int space_node::is_tag() 3188 { 3189 return 0; 3190 } 3191 3192 int space_node::nspaces() 3193 { 3194 return set ? 0 : 1; 3195 } 3196 3197 int space_node::merge_space(hunits h, hunits, hunits) 3198 { 3199 n += h; 3200 return 1; 3201 } 3202 3203 hunits space_node::width() 3204 { 3205 return n; 3206 } 3207 3208 void node::spread_space(int*, hunits*) 3209 { 3210 } 3211 3212 void space_node::spread_space(int *n_spaces, hunits *desired_space) 3213 { 3214 if (!set) { 3215 assert(*n_spaces > 0); 3216 if (*n_spaces == 1) { 3217 n += *desired_space; 3218 *desired_space = H0; 3219 } 3220 else { 3221 hunits extra = *desired_space / *n_spaces; 3222 *desired_space -= extra; 3223 n += extra; 3224 } 3225 *n_spaces -= 1; 3226 set = 1; 3227 } 3228 } 3229 3230 void node::freeze_space() 3231 { 3232 } 3233 3234 void space_node::freeze_space() 3235 { 3236 set = 1; 3237 } 3238 3239 void node::is_escape_colon() 3240 { 3241 } 3242 3243 void space_node::is_escape_colon() 3244 { 3245 was_escape_colon = 1; 3246 } 3247 3248 diverted_space_node::diverted_space_node(vunits d, statem *s, int pop, 3249 node *p) 3250 : node(p, s, pop), n(d) 3251 { 3252 } 3253 3254 diverted_space_node::diverted_space_node(vunits d, node *p) 3255 : node(p), n(d) 3256 { 3257 } 3258 3259 node *diverted_space_node::copy() 3260 { 3261 return new diverted_space_node(n, state, div_nest_level); 3262 } 3263 3264 diverted_copy_file_node::diverted_copy_file_node(symbol s, statem *st, 3265 int pop, node *p) 3266 : node(p, st, pop), filename(s) 3267 { 3268 } 3269 3270 diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p) 3271 : node(p), filename(s) 3272 { 3273 } 3274 3275 node *diverted_copy_file_node::copy() 3276 { 3277 return new diverted_copy_file_node(filename, state, div_nest_level); 3278 } 3279 3280 int node::ends_sentence() 3281 { 3282 return 0; 3283 } 3284 3285 int kern_pair_node::ends_sentence() 3286 { 3287 switch (n2->ends_sentence()) { 3288 case 0: 3289 return 0; 3290 case 1: 3291 return 1; 3292 case 2: 3293 break; 3294 default: 3295 assert(0); 3296 } 3297 return n1->ends_sentence(); 3298 } 3299 3300 int node_list_ends_sentence(node *n) 3301 { 3302 for (; n != 0; n = n->next) 3303 switch (n->ends_sentence()) { 3304 case 0: 3305 return 0; 3306 case 1: 3307 return 1; 3308 case 2: 3309 break; 3310 default: 3311 assert(0); 3312 } 3313 return 2; 3314 } 3315 3316 int dbreak_node::ends_sentence() 3317 { 3318 return node_list_ends_sentence(none); 3319 } 3320 3321 int node::overlaps_horizontally() 3322 { 3323 return 0; 3324 } 3325 3326 int node::overlaps_vertically() 3327 { 3328 return 0; 3329 } 3330 3331 int node::discardable() 3332 { 3333 return 0; 3334 } 3335 3336 int space_node::discardable() 3337 { 3338 return set ? 0 : 1; 3339 } 3340 3341 vunits node::vertical_width() 3342 { 3343 return V0; 3344 } 3345 3346 vunits vline_node::vertical_width() 3347 { 3348 return x; 3349 } 3350 3351 vunits vmotion_node::vertical_width() 3352 { 3353 return n; 3354 } 3355 3356 int node::set_unformat_flag() 3357 { 3358 return 1; 3359 } 3360 3361 int node::character_type() 3362 { 3363 return 0; 3364 } 3365 3366 hunits node::subscript_correction() 3367 { 3368 return H0; 3369 } 3370 3371 hunits node::italic_correction() 3372 { 3373 return H0; 3374 } 3375 3376 hunits node::left_italic_correction() 3377 { 3378 return H0; 3379 } 3380 3381 hunits node::skew() 3382 { 3383 return H0; 3384 } 3385 3386 /* vertical_extent methods */ 3387 3388 void node::vertical_extent(vunits *min, vunits *max) 3389 { 3390 vunits v = vertical_width(); 3391 if (v < V0) { 3392 *min = v; 3393 *max = V0; 3394 } 3395 else { 3396 *max = v; 3397 *min = V0; 3398 } 3399 } 3400 3401 void vline_node::vertical_extent(vunits *min, vunits *max) 3402 { 3403 if (n == 0) 3404 node::vertical_extent(min, max); 3405 else { 3406 vunits cmin, cmax; 3407 n->vertical_extent(&cmin, &cmax); 3408 vunits h = n->size(); 3409 if (x < V0) { 3410 if (-x < h) { 3411 *min = x; 3412 *max = V0; 3413 } 3414 else { 3415 // we print the first character and then move up, so 3416 *max = cmax; 3417 // we print the last character and then move up h 3418 *min = cmin + h; 3419 if (*min > V0) 3420 *min = V0; 3421 *min += x; 3422 } 3423 } 3424 else { 3425 if (x < h) { 3426 *max = x; 3427 *min = V0; 3428 } 3429 else { 3430 // we move down by h and then print the first character, so 3431 *min = cmin + h; 3432 if (*min > V0) 3433 *min = V0; 3434 *max = x + cmax; 3435 } 3436 } 3437 } 3438 } 3439 3440 /* ascii_print methods */ 3441 3442 static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n) 3443 { 3444 if (n == 0) 3445 return; 3446 ascii_print_reverse_node_list(ascii, n->next); 3447 n->ascii_print(ascii); 3448 } 3449 3450 void dbreak_node::ascii_print(ascii_output_file *ascii) 3451 { 3452 ascii_print_reverse_node_list(ascii, none); 3453 } 3454 3455 void kern_pair_node::ascii_print(ascii_output_file *ascii) 3456 { 3457 n1->ascii_print(ascii); 3458 n2->ascii_print(ascii); 3459 } 3460 3461 void node::ascii_print(ascii_output_file *) 3462 { 3463 } 3464 3465 void space_node::ascii_print(ascii_output_file *ascii) 3466 { 3467 if (!n.is_zero()) 3468 ascii->outc(' '); 3469 } 3470 3471 void hmotion_node::ascii_print(ascii_output_file *ascii) 3472 { 3473 // this is pretty arbitrary 3474 if (n >= points_to_units(2)) 3475 ascii->outc(' '); 3476 } 3477 3478 void space_char_hmotion_node::ascii_print(ascii_output_file *ascii) 3479 { 3480 ascii->outc(' '); 3481 } 3482 3483 /* asciify methods */ 3484 3485 void node::asciify(macro *m) 3486 { 3487 m->append(this); 3488 } 3489 3490 void glyph_node::asciify(macro *m) 3491 { 3492 unsigned char c = ci->get_asciify_code(); 3493 if (c == 0) 3494 c = ci->get_ascii_code(); 3495 if (c != 0) { 3496 m->append(c); 3497 delete this; 3498 } 3499 else 3500 m->append(this); 3501 } 3502 3503 void kern_pair_node::asciify(macro *m) 3504 { 3505 n1->asciify(m); 3506 n2->asciify(m); 3507 n1 = n2 = 0; 3508 delete this; 3509 } 3510 3511 static void asciify_reverse_node_list(macro *m, node *n) 3512 { 3513 if (n == 0) 3514 return; 3515 asciify_reverse_node_list(m, n->next); 3516 n->asciify(m); 3517 } 3518 3519 void dbreak_node::asciify(macro *m) 3520 { 3521 asciify_reverse_node_list(m, none); 3522 none = 0; 3523 delete this; 3524 } 3525 3526 void ligature_node::asciify(macro *m) 3527 { 3528 n1->asciify(m); 3529 n2->asciify(m); 3530 n1 = n2 = 0; 3531 delete this; 3532 } 3533 3534 void break_char_node::asciify(macro *m) 3535 { 3536 ch->asciify(m); 3537 ch = 0; 3538 delete this; 3539 } 3540 3541 void italic_corrected_node::asciify(macro *m) 3542 { 3543 n->asciify(m); 3544 n = 0; 3545 delete this; 3546 } 3547 3548 void left_italic_corrected_node::asciify(macro *m) 3549 { 3550 if (n) { 3551 n->asciify(m); 3552 n = 0; 3553 } 3554 delete this; 3555 } 3556 3557 void hmotion_node::asciify(macro *m) 3558 { 3559 if (was_tab) { 3560 m->append('\t'); 3561 delete this; 3562 } 3563 else 3564 m->append(this); 3565 } 3566 3567 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c, 3568 statem *s, int pop, 3569 node *nxt) 3570 : hmotion_node(i, c, s, pop, nxt) 3571 { 3572 } 3573 3574 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c, 3575 node *nxt) 3576 : hmotion_node(i, c, 0, 0, nxt) 3577 { 3578 } 3579 3580 void space_char_hmotion_node::asciify(macro *m) 3581 { 3582 m->append(ESCAPE_SPACE); 3583 delete this; 3584 } 3585 3586 void space_node::asciify(macro *m) 3587 { 3588 if (was_escape_colon) { 3589 m->append(ESCAPE_COLON); 3590 delete this; 3591 } 3592 else 3593 m->append(this); 3594 } 3595 3596 void word_space_node::asciify(macro *m) 3597 { 3598 for (width_list *w = orig_width; w; w = w->next) 3599 m->append(' '); 3600 delete this; 3601 } 3602 3603 void unbreakable_space_node::asciify(macro *m) 3604 { 3605 m->append(ESCAPE_TILDE); 3606 delete this; 3607 } 3608 3609 void line_start_node::asciify(macro *) 3610 { 3611 delete this; 3612 } 3613 3614 void vertical_size_node::asciify(macro *) 3615 { 3616 delete this; 3617 } 3618 3619 breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/, 3620 breakpoint *rest, int /*is_inner*/) 3621 { 3622 return rest; 3623 } 3624 3625 int node::nbreaks() 3626 { 3627 return 0; 3628 } 3629 3630 breakpoint *space_node::get_breakpoints(hunits wd, int ns, 3631 breakpoint *rest, int is_inner) 3632 { 3633 if (next && next->discardable()) 3634 return rest; 3635 breakpoint *bp = new breakpoint; 3636 bp->next = rest; 3637 bp->width = wd; 3638 bp->nspaces = ns; 3639 bp->hyphenated = 0; 3640 if (is_inner) { 3641 assert(rest != 0); 3642 bp->index = rest->index + 1; 3643 bp->nd = rest->nd; 3644 } 3645 else { 3646 bp->nd = this; 3647 bp->index = 0; 3648 } 3649 return bp; 3650 } 3651 3652 int space_node::nbreaks() 3653 { 3654 if (next && next->discardable()) 3655 return 0; 3656 else 3657 return 1; 3658 } 3659 3660 static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp, 3661 int ns, breakpoint *rest) 3662 { 3663 if (p != 0) { 3664 rest = p->get_breakpoints(*widthp, 3665 ns, 3666 node_list_get_breakpoints(p->next, widthp, ns, 3667 rest), 3668 1); 3669 *widthp += p->width(); 3670 } 3671 return rest; 3672 } 3673 3674 breakpoint *dbreak_node::get_breakpoints(hunits wd, int ns, 3675 breakpoint *rest, int is_inner) 3676 { 3677 breakpoint *bp = new breakpoint; 3678 bp->next = rest; 3679 bp->width = wd; 3680 for (node *tem = pre; tem != 0; tem = tem->next) 3681 bp->width += tem->width(); 3682 bp->nspaces = ns; 3683 bp->hyphenated = 1; 3684 if (is_inner) { 3685 assert(rest != 0); 3686 bp->index = rest->index + 1; 3687 bp->nd = rest->nd; 3688 } 3689 else { 3690 bp->nd = this; 3691 bp->index = 0; 3692 } 3693 return node_list_get_breakpoints(none, &wd, ns, bp); 3694 } 3695 3696 int dbreak_node::nbreaks() 3697 { 3698 int i = 1; 3699 for (node *tem = none; tem != 0; tem = tem->next) 3700 i += tem->nbreaks(); 3701 return i; 3702 } 3703 3704 void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/) 3705 { 3706 assert(0); 3707 } 3708 3709 void space_node::split(int where, node **pre, node **post) 3710 { 3711 assert(where == 0); 3712 *pre = next; 3713 *post = 0; 3714 delete this; 3715 } 3716 3717 static void node_list_split(node *p, int *wherep, node **prep, node **postp) 3718 { 3719 if (p == 0) 3720 return; 3721 int nb = p->nbreaks(); 3722 node_list_split(p->next, wherep, prep, postp); 3723 if (*wherep < 0) { 3724 p->next = *postp; 3725 *postp = p; 3726 } 3727 else if (*wherep < nb) { 3728 p->next = *prep; 3729 p->split(*wherep, prep, postp); 3730 } 3731 else { 3732 p->next = *prep; 3733 *prep = p; 3734 } 3735 *wherep -= nb; 3736 } 3737 3738 void dbreak_node::split(int where, node **prep, node **postp) 3739 { 3740 assert(where >= 0); 3741 if (where == 0) { 3742 *postp = post; 3743 post = 0; 3744 if (pre == 0) 3745 *prep = next; 3746 else { 3747 node *tem; 3748 for (tem = pre; tem->next != 0; tem = tem->next) 3749 ; 3750 tem->next = next; 3751 *prep = pre; 3752 } 3753 pre = 0; 3754 delete this; 3755 } 3756 else { 3757 *prep = next; 3758 where -= 1; 3759 node_list_split(none, &where, prep, postp); 3760 none = 0; 3761 delete this; 3762 } 3763 } 3764 3765 hyphenation_type node::get_hyphenation_type() 3766 { 3767 return HYPHEN_BOUNDARY; 3768 } 3769 3770 hyphenation_type dbreak_node::get_hyphenation_type() 3771 { 3772 return HYPHEN_INHIBIT; 3773 } 3774 3775 hyphenation_type kern_pair_node::get_hyphenation_type() 3776 { 3777 return HYPHEN_MIDDLE; 3778 } 3779 3780 hyphenation_type dummy_node::get_hyphenation_type() 3781 { 3782 return HYPHEN_MIDDLE; 3783 } 3784 3785 hyphenation_type transparent_dummy_node::get_hyphenation_type() 3786 { 3787 return HYPHEN_MIDDLE; 3788 } 3789 3790 hyphenation_type hmotion_node::get_hyphenation_type() 3791 { 3792 return HYPHEN_MIDDLE; 3793 } 3794 3795 hyphenation_type space_char_hmotion_node::get_hyphenation_type() 3796 { 3797 return HYPHEN_MIDDLE; 3798 } 3799 3800 hyphenation_type overstrike_node::get_hyphenation_type() 3801 { 3802 return HYPHEN_MIDDLE; 3803 } 3804 3805 hyphenation_type space_node::get_hyphenation_type() 3806 { 3807 if (was_escape_colon) 3808 return HYPHEN_MIDDLE; 3809 return HYPHEN_BOUNDARY; 3810 } 3811 3812 hyphenation_type unbreakable_space_node::get_hyphenation_type() 3813 { 3814 return HYPHEN_MIDDLE; 3815 } 3816 3817 int node::interpret(macro *) 3818 { 3819 return 0; 3820 } 3821 3822 special_node::special_node(const macro &m, int n) 3823 : mac(m), no_init_string(n) 3824 { 3825 font_size fs = curenv->get_font_size(); 3826 int char_height = curenv->get_char_height(); 3827 int char_slant = curenv->get_char_slant(); 3828 int fontno = env_definite_font(curenv); 3829 tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno); 3830 if (curenv->is_composite()) 3831 tf = tf->get_plain(); 3832 gcol = curenv->get_glyph_color(); 3833 fcol = curenv->get_fill_color(); 3834 is_special = 1; 3835 } 3836 3837 special_node::special_node(const macro &m, tfont *t, 3838 color *gc, color *fc, 3839 statem *s, int pop, 3840 int n) 3841 : node(0, s, pop), mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n) 3842 { 3843 is_special = 1; 3844 } 3845 3846 int special_node::same(node *n) 3847 { 3848 return mac == ((special_node *)n)->mac 3849 && tf == ((special_node *)n)->tf 3850 && gcol == ((special_node *)n)->gcol 3851 && fcol == ((special_node *)n)->fcol 3852 && no_init_string == ((special_node *)n)->no_init_string; 3853 } 3854 3855 const char *special_node::type() 3856 { 3857 return "special_node"; 3858 } 3859 3860 int special_node::ends_sentence() 3861 { 3862 return 2; 3863 } 3864 3865 int special_node::force_tprint() 3866 { 3867 return 0; 3868 } 3869 3870 int special_node::is_tag() 3871 { 3872 return 0; 3873 } 3874 3875 node *special_node::copy() 3876 { 3877 return new special_node(mac, tf, gcol, fcol, state, div_nest_level, 3878 no_init_string); 3879 } 3880 3881 void special_node::tprint_start(troff_output_file *out) 3882 { 3883 out->start_special(tf, gcol, fcol, no_init_string); 3884 } 3885 3886 void special_node::tprint_char(troff_output_file *out, unsigned char c) 3887 { 3888 out->special_char(c); 3889 } 3890 3891 void special_node::tprint_end(troff_output_file *out) 3892 { 3893 out->end_special(); 3894 } 3895 3896 tfont *special_node::get_tfont() 3897 { 3898 return tf; 3899 } 3900 3901 /* suppress_node */ 3902 3903 suppress_node::suppress_node(int on_or_off, int issue_limits) 3904 : is_on(on_or_off), emit_limits(issue_limits), filename(0), position(0), 3905 image_id(0) 3906 { 3907 } 3908 3909 suppress_node::suppress_node(symbol f, char p, int id) 3910 : is_on(2), emit_limits(0), filename(f), position(p), image_id(id) 3911 { 3912 is_special = 1; 3913 } 3914 3915 suppress_node::suppress_node(int issue_limits, int on_or_off, 3916 symbol f, char p, int id, 3917 statem *s, int pop) 3918 : node(0, s, pop), is_on(on_or_off), emit_limits(issue_limits), filename(f), 3919 position(p), image_id(id) 3920 { 3921 } 3922 3923 int suppress_node::same(node *n) 3924 { 3925 return ((is_on == ((suppress_node *)n)->is_on) 3926 && (emit_limits == ((suppress_node *)n)->emit_limits) 3927 && (filename == ((suppress_node *)n)->filename) 3928 && (position == ((suppress_node *)n)->position) 3929 && (image_id == ((suppress_node *)n)->image_id)); 3930 } 3931 3932 const char *suppress_node::type() 3933 { 3934 return "suppress_node"; 3935 } 3936 3937 node *suppress_node::copy() 3938 { 3939 return new suppress_node(emit_limits, is_on, filename, position, image_id, 3940 state, div_nest_level); 3941 } 3942 3943 /* tag_node */ 3944 3945 tag_node::tag_node() 3946 : delayed(0) 3947 { 3948 is_special = 1; 3949 } 3950 3951 tag_node::tag_node(string s, int delay) 3952 : tag_string(s), delayed(delay) 3953 { 3954 is_special = !delay; 3955 } 3956 3957 tag_node::tag_node(string s, statem *st, int pop, int delay) 3958 : node(0, st, pop), tag_string(s), delayed(delay) 3959 { 3960 is_special = !delay; 3961 } 3962 3963 node *tag_node::copy() 3964 { 3965 return new tag_node(tag_string, state, div_nest_level, delayed); 3966 } 3967 3968 void tag_node::tprint(troff_output_file *out) 3969 { 3970 if (delayed) 3971 out->add_to_tag_list(tag_string); 3972 else 3973 out->state.add_tag(out->fp, tag_string); 3974 } 3975 3976 int tag_node::same(node *nd) 3977 { 3978 return tag_string == ((tag_node *)nd)->tag_string 3979 && delayed == ((tag_node *)nd)->delayed; 3980 } 3981 3982 const char *tag_node::type() 3983 { 3984 return "tag_node"; 3985 } 3986 3987 int tag_node::force_tprint() 3988 { 3989 return !delayed; 3990 } 3991 3992 int tag_node::is_tag() 3993 { 3994 return !delayed; 3995 } 3996 3997 int tag_node::ends_sentence() 3998 { 3999 return 2; 4000 } 4001 4002 int get_reg_int(const char *p) 4003 { 4004 reg *r = (reg *)number_reg_dictionary.lookup(p); 4005 units prev_value; 4006 if (r && (r->get_value(&prev_value))) 4007 return (int)prev_value; 4008 else 4009 warning(WARN_REG, "number register `%1' not defined", p); 4010 return 0; 4011 } 4012 4013 const char *get_reg_str(const char *p) 4014 { 4015 reg *r = (reg *)number_reg_dictionary.lookup(p); 4016 if (r) 4017 return r->get_string(); 4018 else 4019 warning(WARN_REG, "register `%1' not defined", p); 4020 return 0; 4021 } 4022 4023 void suppress_node::put(troff_output_file *out, const char *s) 4024 { 4025 int i = 0; 4026 while (s[i] != (char)0) { 4027 out->special_char(s[i]); 4028 i++; 4029 } 4030 } 4031 4032 /* 4033 * We need to remember the start of the image and its name. 4034 */ 4035 4036 static char last_position = 0; 4037 static const char *last_image_filename = 0; 4038 static int last_image_id = 0; 4039 4040 inline int min(int a, int b) 4041 { 4042 return a < b ? a : b; 4043 } 4044 4045 /* 4046 * tprint - if (is_on == 2) 4047 * remember current position (l, r, c, i) and filename 4048 * else 4049 * if (emit_limits) 4050 * if (html) 4051 * emit image tag 4052 * else 4053 * emit postscript bounds for image 4054 * else 4055 * if (suppress boolean differs from current state) 4056 * alter state 4057 * reset registers 4058 * record current page 4059 * set low water mark. 4060 */ 4061 4062 void suppress_node::tprint(troff_output_file *out) 4063 { 4064 int current_page = topdiv->get_page_number(); 4065 // firstly check to see whether this suppress node contains 4066 // an image filename & position. 4067 if (is_on == 2) { 4068 // remember position and filename 4069 last_position = position; 4070 char *tem = (char *)last_image_filename; 4071 last_image_filename = strsave(filename.contents()); 4072 if (tem) 4073 a_delete tem; 4074 last_image_id = image_id; 4075 // printf("start of image and page = %d\n", current_page); 4076 } 4077 else { 4078 // now check whether the suppress node requires us to issue limits. 4079 if (emit_limits) { 4080 char name[8192]; 4081 // remember that the filename will contain a %d in which the 4082 // last_image_id is placed 4083 if (last_image_filename == (char *) 0) 4084 *name = '\0'; 4085 else 4086 sprintf(name, last_image_filename, last_image_id); 4087 if (is_html) { 4088 switch (last_position) { 4089 case 'c': 4090 out->start_special(); 4091 put(out, "devtag:.centered-image"); 4092 break; 4093 case 'r': 4094 out->start_special(); 4095 put(out, "devtag:.right-image"); 4096 break; 4097 case 'l': 4098 out->start_special(); 4099 put(out, "devtag:.left-image"); 4100 break; 4101 case 'i': 4102 ; 4103 default: 4104 ; 4105 } 4106 out->end_special(); 4107 out->start_special(); 4108 put(out, "devtag:.auto-image "); 4109 put(out, name); 4110 out->end_special(); 4111 } 4112 else { 4113 // postscript (or other device) 4114 if (suppress_start_page > 0 && current_page != suppress_start_page) 4115 error("suppression limit registers span more than one page;\n" 4116 "image description %1 will be wrong", image_no); 4117 // if (topdiv->get_page_number() != suppress_start_page) 4118 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n", 4119 // topdiv->get_page_number(), suppress_start_page); 4120 4121 // remember that the filename will contain a %d in which the 4122 // image_no is placed 4123 fprintf(stderr, 4124 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n", 4125 topdiv->get_page_number(), 4126 get_reg_int("opminx"), get_reg_int("opminy"), 4127 get_reg_int("opmaxx"), get_reg_int("opmaxy"), 4128 // page offset + line length 4129 get_reg_int(".o") + get_reg_int(".l"), 4130 name, hresolution, vresolution, get_reg_str(".F")); 4131 fflush(stderr); 4132 } 4133 } 4134 else { 4135 if (is_on) { 4136 out->on(); 4137 // lastly we reset the output registers 4138 reset_output_registers(); 4139 } 4140 else 4141 out->off(); 4142 suppress_start_page = current_page; 4143 } 4144 } 4145 } 4146 4147 int suppress_node::force_tprint() 4148 { 4149 return is_on; 4150 } 4151 4152 int suppress_node::is_tag() 4153 { 4154 return is_on; 4155 } 4156 4157 hunits suppress_node::width() 4158 { 4159 return H0; 4160 } 4161 4162 /* composite_node */ 4163 4164 class composite_node : public charinfo_node { 4165 node *n; 4166 tfont *tf; 4167 public: 4168 composite_node(node *, charinfo *, tfont *, statem *, int, node * = 0); 4169 ~composite_node(); 4170 node *copy(); 4171 hunits width(); 4172 node *last_char_node(); 4173 units size(); 4174 void tprint(troff_output_file *); 4175 hyphenation_type get_hyphenation_type(); 4176 void ascii_print(ascii_output_file *); 4177 void asciify(macro *); 4178 hyphen_list *get_hyphen_list(hyphen_list *, int *); 4179 node *add_self(node *, hyphen_list **); 4180 tfont *get_tfont(); 4181 int same(node *); 4182 const char *type(); 4183 int force_tprint(); 4184 int is_tag(); 4185 void vertical_extent(vunits *, vunits *); 4186 vunits vertical_width(); 4187 }; 4188 4189 composite_node::composite_node(node *p, charinfo *c, tfont *t, statem *s, 4190 int pop, node *x) 4191 : charinfo_node(c, s, pop, x), n(p), tf(t) 4192 { 4193 } 4194 4195 composite_node::~composite_node() 4196 { 4197 delete_node_list(n); 4198 } 4199 4200 node *composite_node::copy() 4201 { 4202 return new composite_node(copy_node_list(n), ci, tf, state, div_nest_level); 4203 } 4204 4205 hunits composite_node::width() 4206 { 4207 hunits x; 4208 if (tf->get_constant_space(&x)) 4209 return x; 4210 x = H0; 4211 for (node *tem = n; tem; tem = tem->next) 4212 x += tem->width(); 4213 hunits offset; 4214 if (tf->get_bold(&offset)) 4215 x += offset; 4216 x += tf->get_track_kern(); 4217 return x; 4218 } 4219 4220 node *composite_node::last_char_node() 4221 { 4222 return this; 4223 } 4224 4225 vunits composite_node::vertical_width() 4226 { 4227 vunits v = V0; 4228 for (node *tem = n; tem; tem = tem->next) 4229 v += tem->vertical_width(); 4230 return v; 4231 } 4232 4233 units composite_node::size() 4234 { 4235 return tf->get_size().to_units(); 4236 } 4237 4238 hyphenation_type composite_node::get_hyphenation_type() 4239 { 4240 return HYPHEN_MIDDLE; 4241 } 4242 4243 void composite_node::asciify(macro *m) 4244 { 4245 unsigned char c = ci->get_asciify_code(); 4246 if (c == 0) 4247 c = ci->get_ascii_code(); 4248 if (c != 0) { 4249 m->append(c); 4250 delete this; 4251 } 4252 else 4253 m->append(this); 4254 } 4255 4256 void composite_node::ascii_print(ascii_output_file *ascii) 4257 { 4258 unsigned char c = ci->get_ascii_code(); 4259 if (c != 0) 4260 ascii->outc(c); 4261 else 4262 ascii->outs(ci->nm.contents()); 4263 4264 } 4265 4266 hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail, int *count) 4267 { 4268 (*count)++; 4269 return new hyphen_list(ci->get_hyphenation_code(), tail); 4270 } 4271 4272 node *composite_node::add_self(node *nn, hyphen_list **p) 4273 { 4274 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); 4275 next = nn; 4276 nn = this; 4277 if ((*p)->hyphen) 4278 nn = nn->add_discretionary_hyphen(); 4279 hyphen_list *pp = *p; 4280 *p = (*p)->next; 4281 delete pp; 4282 return nn; 4283 } 4284 4285 tfont *composite_node::get_tfont() 4286 { 4287 return tf; 4288 } 4289 4290 node *reverse_node_list(node *n) 4291 { 4292 node *r = 0; 4293 while (n) { 4294 node *tem = n; 4295 n = n->next; 4296 tem->next = r; 4297 r = tem; 4298 } 4299 return r; 4300 } 4301 4302 void composite_node::vertical_extent(vunits *minimum, vunits *maximum) 4303 { 4304 n = reverse_node_list(n); 4305 node_list_vertical_extent(n, minimum, maximum); 4306 n = reverse_node_list(n); 4307 } 4308 4309 width_list::width_list(hunits w, hunits s) 4310 : width(w), sentence_width(s), next(0) 4311 { 4312 } 4313 4314 width_list::width_list(width_list *w) 4315 : width(w->width), sentence_width(w->sentence_width), next(0) 4316 { 4317 } 4318 4319 word_space_node::word_space_node(hunits d, color *c, width_list *w, node *x) 4320 : space_node(d, c, x), orig_width(w), unformat(0) 4321 { 4322 } 4323 4324 word_space_node::word_space_node(hunits d, int s, color *c, width_list *w, 4325 int flag, statem *st, int pop, node *x) 4326 : space_node(d, s, 0, c, st, pop, x), orig_width(w), unformat(flag) 4327 { 4328 } 4329 4330 word_space_node::~word_space_node() 4331 { 4332 width_list *w = orig_width; 4333 while (w != 0) { 4334 width_list *tmp = w; 4335 w = w->next; 4336 delete tmp; 4337 } 4338 } 4339 4340 node *word_space_node::copy() 4341 { 4342 assert(orig_width != 0); 4343 width_list *w_old_curr = orig_width; 4344 width_list *w_new_curr = new width_list(w_old_curr); 4345 width_list *w_new = w_new_curr; 4346 w_old_curr = w_old_curr->next; 4347 while (w_old_curr != 0) { 4348 w_new_curr->next = new width_list(w_old_curr); 4349 w_new_curr = w_new_curr->next; 4350 w_old_curr = w_old_curr->next; 4351 } 4352 return new word_space_node(n, set, col, w_new, unformat, state, 4353 div_nest_level); 4354 } 4355 4356 int word_space_node::set_unformat_flag() 4357 { 4358 unformat = 1; 4359 return 1; 4360 } 4361 4362 void word_space_node::tprint(troff_output_file *out) 4363 { 4364 out->fill_color(col); 4365 out->word_marker(); 4366 out->right(n); 4367 } 4368 4369 int word_space_node::merge_space(hunits h, hunits sw, hunits ssw) 4370 { 4371 n += h; 4372 assert(orig_width != 0); 4373 width_list *w = orig_width; 4374 for (; w->next; w = w->next) 4375 ; 4376 w->next = new width_list(sw, ssw); 4377 return 1; 4378 } 4379 4380 unbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x) 4381 : word_space_node(d, c, 0, x) 4382 { 4383 } 4384 4385 unbreakable_space_node::unbreakable_space_node(hunits d, int s, 4386 color *c, statem *st, int pop, 4387 node *x) 4388 : word_space_node(d, s, c, 0, 0, st, pop, x) 4389 { 4390 } 4391 4392 node *unbreakable_space_node::copy() 4393 { 4394 return new unbreakable_space_node(n, set, col, state, div_nest_level); 4395 } 4396 4397 int unbreakable_space_node::force_tprint() 4398 { 4399 return 0; 4400 } 4401 4402 int unbreakable_space_node::is_tag() 4403 { 4404 return 0; 4405 } 4406 4407 breakpoint *unbreakable_space_node::get_breakpoints(hunits, int, 4408 breakpoint *rest, int) 4409 { 4410 return rest; 4411 } 4412 4413 int unbreakable_space_node::nbreaks() 4414 { 4415 return 0; 4416 } 4417 4418 void unbreakable_space_node::split(int, node **, node **) 4419 { 4420 assert(0); 4421 } 4422 4423 int unbreakable_space_node::merge_space(hunits, hunits, hunits) 4424 { 4425 return 0; 4426 } 4427 4428 hvpair::hvpair() 4429 { 4430 } 4431 4432 draw_node::draw_node(char c, hvpair *p, int np, font_size s, 4433 color *gc, color *fc) 4434 : npoints(np), sz(s), gcol(gc), fcol(fc), code(c) 4435 { 4436 point = new hvpair[npoints]; 4437 for (int i = 0; i < npoints; i++) 4438 point[i] = p[i]; 4439 } 4440 4441 draw_node::draw_node(char c, hvpair *p, int np, font_size s, 4442 color *gc, color *fc, statem *st, int pop) 4443 : node(0, st, pop), npoints(np), sz(s), gcol(gc), fcol(fc), code(c) 4444 { 4445 point = new hvpair[npoints]; 4446 for (int i = 0; i < npoints; i++) 4447 point[i] = p[i]; 4448 } 4449 4450 int draw_node::same(node *n) 4451 { 4452 draw_node *nd = (draw_node *)n; 4453 if (code != nd->code || npoints != nd->npoints || sz != nd->sz 4454 || gcol != nd->gcol || fcol != nd->fcol) 4455 return 0; 4456 for (int i = 0; i < npoints; i++) 4457 if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v) 4458 return 0; 4459 return 1; 4460 } 4461 4462 const char *draw_node::type() 4463 { 4464 return "draw_node"; 4465 } 4466 4467 int draw_node::force_tprint() 4468 { 4469 return 0; 4470 } 4471 4472 int draw_node::is_tag() 4473 { 4474 return 0; 4475 } 4476 4477 draw_node::~draw_node() 4478 { 4479 if (point) 4480 a_delete point; 4481 } 4482 4483 hunits draw_node::width() 4484 { 4485 hunits x = H0; 4486 for (int i = 0; i < npoints; i++) 4487 x += point[i].h; 4488 return x; 4489 } 4490 4491 vunits draw_node::vertical_width() 4492 { 4493 if (code == 'e') 4494 return V0; 4495 vunits x = V0; 4496 for (int i = 0; i < npoints; i++) 4497 x += point[i].v; 4498 return x; 4499 } 4500 4501 node *draw_node::copy() 4502 { 4503 return new draw_node(code, point, npoints, sz, gcol, fcol, state, 4504 div_nest_level); 4505 } 4506 4507 void draw_node::tprint(troff_output_file *out) 4508 { 4509 out->draw(code, point, npoints, sz, gcol, fcol); 4510 } 4511 4512 /* tprint methods */ 4513 4514 void glyph_node::tprint(troff_output_file *out) 4515 { 4516 tfont *ptf = tf->get_plain(); 4517 if (ptf == tf) 4518 out->put_char_width(ci, ptf, gcol, fcol, width(), H0); 4519 else { 4520 hunits offset; 4521 int bold = tf->get_bold(&offset); 4522 hunits w = ptf->get_width(ci); 4523 hunits k = H0; 4524 hunits x; 4525 int cs = tf->get_constant_space(&x); 4526 if (cs) { 4527 x -= w; 4528 if (bold) 4529 x -= offset; 4530 hunits x2 = x/2; 4531 out->right(x2); 4532 k = x - x2; 4533 } 4534 else 4535 k = tf->get_track_kern(); 4536 if (bold) { 4537 out->put_char(ci, ptf, gcol, fcol); 4538 out->right(offset); 4539 } 4540 out->put_char_width(ci, ptf, gcol, fcol, w, k); 4541 } 4542 } 4543 4544 void glyph_node::zero_width_tprint(troff_output_file *out) 4545 { 4546 tfont *ptf = tf->get_plain(); 4547 hunits offset; 4548 int bold = tf->get_bold(&offset); 4549 hunits x; 4550 int cs = tf->get_constant_space(&x); 4551 if (cs) { 4552 x -= ptf->get_width(ci); 4553 if (bold) 4554 x -= offset; 4555 x = x/2; 4556 out->right(x); 4557 } 4558 out->put_char(ci, ptf, gcol, fcol); 4559 if (bold) { 4560 out->right(offset); 4561 out->put_char(ci, ptf, gcol, fcol); 4562 out->right(-offset); 4563 } 4564 if (cs) 4565 out->right(-x); 4566 } 4567 4568 void break_char_node::tprint(troff_output_file *t) 4569 { 4570 ch->tprint(t); 4571 } 4572 4573 void break_char_node::zero_width_tprint(troff_output_file *t) 4574 { 4575 ch->zero_width_tprint(t); 4576 } 4577 4578 void hline_node::tprint(troff_output_file *out) 4579 { 4580 if (x < H0) { 4581 out->right(x); 4582 x = -x; 4583 } 4584 if (n == 0) { 4585 out->right(x); 4586 return; 4587 } 4588 hunits w = n->width(); 4589 if (w <= H0) { 4590 error("horizontal line drawing character must have positive width"); 4591 out->right(x); 4592 return; 4593 } 4594 int i = int(x/w); 4595 if (i == 0) { 4596 hunits xx = x - w; 4597 hunits xx2 = xx/2; 4598 out->right(xx2); 4599 if (out->is_on()) 4600 n->tprint(out); 4601 out->right(xx - xx2); 4602 } 4603 else { 4604 hunits rem = x - w*i; 4605 if (rem > H0) { 4606 if (n->overlaps_horizontally()) { 4607 if (out->is_on()) 4608 n->tprint(out); 4609 out->right(rem - w); 4610 } 4611 else 4612 out->right(rem); 4613 } 4614 while (--i >= 0) 4615 if (out->is_on()) 4616 n->tprint(out); 4617 } 4618 } 4619 4620 void vline_node::tprint(troff_output_file *out) 4621 { 4622 if (n == 0) { 4623 out->down(x); 4624 return; 4625 } 4626 vunits h = n->size(); 4627 int overlaps = n->overlaps_vertically(); 4628 vunits y = x; 4629 if (y < V0) { 4630 y = -y; 4631 int i = y / h; 4632 vunits rem = y - i*h; 4633 if (i == 0) { 4634 out->right(n->width()); 4635 out->down(-rem); 4636 } 4637 else { 4638 while (--i > 0) { 4639 n->zero_width_tprint(out); 4640 out->down(-h); 4641 } 4642 if (overlaps) { 4643 n->zero_width_tprint(out); 4644 out->down(-rem); 4645 if (out->is_on()) 4646 n->tprint(out); 4647 out->down(-h); 4648 } 4649 else { 4650 if (out->is_on()) 4651 n->tprint(out); 4652 out->down(-h - rem); 4653 } 4654 } 4655 } 4656 else { 4657 int i = y / h; 4658 vunits rem = y - i*h; 4659 if (i == 0) { 4660 out->down(rem); 4661 out->right(n->width()); 4662 } 4663 else { 4664 out->down(h); 4665 if (overlaps) 4666 n->zero_width_tprint(out); 4667 out->down(rem); 4668 while (--i > 0) { 4669 n->zero_width_tprint(out); 4670 out->down(h); 4671 } 4672 if (out->is_on()) 4673 n->tprint(out); 4674 } 4675 } 4676 } 4677 4678 void zero_width_node::tprint(troff_output_file *out) 4679 { 4680 if (!n) 4681 return; 4682 if (!n->next) { 4683 n->zero_width_tprint(out); 4684 return; 4685 } 4686 int hpos = out->get_hpos(); 4687 int vpos = out->get_vpos(); 4688 node *tem = n; 4689 while (tem) { 4690 tem->tprint(out); 4691 tem = tem->next; 4692 } 4693 out->moveto(hpos, vpos); 4694 } 4695 4696 void overstrike_node::tprint(troff_output_file *out) 4697 { 4698 hunits pos = H0; 4699 for (node *tem = list; tem; tem = tem->next) { 4700 hunits x = (max_width - tem->width())/2; 4701 out->right(x - pos); 4702 pos = x; 4703 tem->zero_width_tprint(out); 4704 } 4705 out->right(max_width - pos); 4706 } 4707 4708 void bracket_node::tprint(troff_output_file *out) 4709 { 4710 if (list == 0) 4711 return; 4712 int npieces = 0; 4713 node *tem; 4714 for (tem = list; tem; tem = tem->next) 4715 ++npieces; 4716 vunits h = list->size(); 4717 vunits totalh = h*npieces; 4718 vunits y = (totalh - h)/2; 4719 out->down(y); 4720 for (tem = list; tem; tem = tem->next) { 4721 tem->zero_width_tprint(out); 4722 out->down(-h); 4723 } 4724 out->right(max_width); 4725 out->down(totalh - y); 4726 } 4727 4728 void node::tprint(troff_output_file *) 4729 { 4730 } 4731 4732 void node::zero_width_tprint(troff_output_file *out) 4733 { 4734 int hpos = out->get_hpos(); 4735 int vpos = out->get_vpos(); 4736 tprint(out); 4737 out->moveto(hpos, vpos); 4738 } 4739 4740 void space_node::tprint(troff_output_file *out) 4741 { 4742 out->fill_color(col); 4743 out->right(n); 4744 } 4745 4746 void hmotion_node::tprint(troff_output_file *out) 4747 { 4748 out->fill_color(col); 4749 out->right(n); 4750 } 4751 4752 void space_char_hmotion_node::tprint(troff_output_file *out) 4753 { 4754 out->fill_color(col); 4755 if (is_html) { 4756 // we emit the space width as a negative glyph index 4757 out->flush_tbuf(); 4758 out->do_motion(); 4759 out->put('N'); 4760 out->put(-n.to_units()); 4761 out->put('\n'); 4762 } 4763 out->right(n); 4764 } 4765 4766 void vmotion_node::tprint(troff_output_file *out) 4767 { 4768 out->fill_color(col); 4769 out->down(n); 4770 } 4771 4772 void kern_pair_node::tprint(troff_output_file *out) 4773 { 4774 n1->tprint(out); 4775 out->right(amount); 4776 n2->tprint(out); 4777 } 4778 4779 static void tprint_reverse_node_list(troff_output_file *out, node *n) 4780 { 4781 if (n == 0) 4782 return; 4783 tprint_reverse_node_list(out, n->next); 4784 n->tprint(out); 4785 } 4786 4787 void dbreak_node::tprint(troff_output_file *out) 4788 { 4789 tprint_reverse_node_list(out, none); 4790 } 4791 4792 void composite_node::tprint(troff_output_file *out) 4793 { 4794 hunits bold_offset; 4795 int is_bold = tf->get_bold(&bold_offset); 4796 hunits track_kern = tf->get_track_kern(); 4797 hunits constant_space; 4798 int is_constant_spaced = tf->get_constant_space(&constant_space); 4799 hunits x = H0; 4800 if (is_constant_spaced) { 4801 x = constant_space; 4802 for (node *tem = n; tem; tem = tem->next) 4803 x -= tem->width(); 4804 if (is_bold) 4805 x -= bold_offset; 4806 hunits x2 = x/2; 4807 out->right(x2); 4808 x -= x2; 4809 } 4810 if (is_bold) { 4811 int hpos = out->get_hpos(); 4812 int vpos = out->get_vpos(); 4813 tprint_reverse_node_list(out, n); 4814 out->moveto(hpos, vpos); 4815 out->right(bold_offset); 4816 } 4817 tprint_reverse_node_list(out, n); 4818 if (is_constant_spaced) 4819 out->right(x); 4820 else 4821 out->right(track_kern); 4822 } 4823 4824 node *make_composite_node(charinfo *s, environment *env) 4825 { 4826 int fontno = env_definite_font(env); 4827 if (fontno < 0) { 4828 error("no current font"); 4829 return 0; 4830 } 4831 assert(fontno < font_table_size && font_table[fontno] != 0); 4832 node *n = charinfo_to_node_list(s, env); 4833 font_size fs = env->get_font_size(); 4834 int char_height = env->get_char_height(); 4835 int char_slant = env->get_char_slant(); 4836 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, 4837 fontno); 4838 if (env->is_composite()) 4839 tf = tf->get_plain(); 4840 return new composite_node(n, s, tf, 0, 0, 0); 4841 } 4842 4843 node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0) 4844 { 4845 int fontno = env_definite_font(env); 4846 if (fontno < 0) { 4847 error("no current font"); 4848 return 0; 4849 } 4850 assert(fontno < font_table_size && font_table[fontno] != 0); 4851 int fn = fontno; 4852 int found = font_table[fontno]->contains(s); 4853 if (!found) { 4854 macro *mac = s->get_macro(); 4855 if (mac && s->is_fallback()) 4856 return make_composite_node(s, env); 4857 if (s->numbered()) { 4858 if (!no_error_message) 4859 warning(WARN_CHAR, "can't find numbered character %1", 4860 s->get_number()); 4861 return 0; 4862 } 4863 special_font_list *sf = font_table[fontno]->sf; 4864 while (sf != 0 && !found) { 4865 fn = sf->n; 4866 if (font_table[fn]) 4867 found = font_table[fn]->contains(s); 4868 sf = sf->next; 4869 } 4870 if (!found) { 4871 symbol f = font_table[fontno]->get_name(); 4872 string gl(f.contents()); 4873 gl += ' '; 4874 gl += s->nm.contents(); 4875 gl += '\0'; 4876 charinfo *ci = get_charinfo(symbol(gl.contents())); 4877 if (ci && ci->get_macro()) 4878 return make_composite_node(ci, env); 4879 } 4880 if (!found) { 4881 sf = global_special_fonts; 4882 while (sf != 0 && !found) { 4883 fn = sf->n; 4884 if (font_table[fn]) 4885 found = font_table[fn]->contains(s); 4886 sf = sf->next; 4887 } 4888 } 4889 if (!found) 4890 if (mac && s->is_special()) 4891 return make_composite_node(s, env); 4892 if (!found) { 4893 for (fn = 0; fn < font_table_size; fn++) 4894 if (font_table[fn] 4895 && font_table[fn]->is_special() 4896 && font_table[fn]->contains(s)) { 4897 found = 1; 4898 break; 4899 } 4900 } 4901 if (!found) { 4902 if (!no_error_message && s->first_time_not_found()) { 4903 unsigned char input_code = s->get_ascii_code(); 4904 if (input_code != 0) { 4905 if (csgraph(input_code)) 4906 warning(WARN_CHAR, "can't find character `%1'", input_code); 4907 else 4908 warning(WARN_CHAR, "can't find character with input code %1", 4909 int(input_code)); 4910 } 4911 else if (s->nm.contents()) 4912 warning(WARN_CHAR, "can't find special character `%1'", 4913 s->nm.contents()); 4914 } 4915 return 0; 4916 } 4917 } 4918 font_size fs = env->get_font_size(); 4919 int char_height = env->get_char_height(); 4920 int char_slant = env->get_char_slant(); 4921 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn); 4922 if (env->is_composite()) 4923 tf = tf->get_plain(); 4924 color *gcol = env->get_glyph_color(); 4925 color *fcol = env->get_fill_color(); 4926 return new glyph_node(s, tf, gcol, fcol, 0, 0); 4927 } 4928 4929 node *make_node(charinfo *ci, environment *env) 4930 { 4931 switch (ci->get_special_translation()) { 4932 case charinfo::TRANSLATE_SPACE: 4933 return new space_char_hmotion_node(env->get_space_width(), 4934 env->get_fill_color()); 4935 case charinfo::TRANSLATE_STRETCHABLE_SPACE: 4936 return new unbreakable_space_node(env->get_space_width(), 4937 env->get_fill_color()); 4938 case charinfo::TRANSLATE_DUMMY: 4939 return new dummy_node; 4940 case charinfo::TRANSLATE_HYPHEN_INDICATOR: 4941 error("translation to \\% ignored in this context"); 4942 break; 4943 } 4944 charinfo *tem = ci->get_translation(); 4945 if (tem) 4946 ci = tem; 4947 macro *mac = ci->get_macro(); 4948 if (mac && ci->is_normal()) 4949 return make_composite_node(ci, env); 4950 else 4951 return make_glyph_node(ci, env); 4952 } 4953 4954 int character_exists(charinfo *ci, environment *env) 4955 { 4956 if (ci->get_special_translation() != charinfo::TRANSLATE_NONE) 4957 return 1; 4958 charinfo *tem = ci->get_translation(); 4959 if (tem) 4960 ci = tem; 4961 if (ci->get_macro()) 4962 return 1; 4963 node *nd = make_glyph_node(ci, env, 1); 4964 if (nd) { 4965 delete nd; 4966 return 1; 4967 } 4968 return 0; 4969 } 4970 4971 node *node::add_char(charinfo *ci, environment *env, 4972 hunits *widthp, int *spacep, node **glyph_comp_np) 4973 { 4974 node *res; 4975 switch (ci->get_special_translation()) { 4976 case charinfo::TRANSLATE_SPACE: 4977 res = new space_char_hmotion_node(env->get_space_width(), 4978 env->get_fill_color(), this); 4979 *widthp += res->width(); 4980 return res; 4981 case charinfo::TRANSLATE_STRETCHABLE_SPACE: 4982 res = new unbreakable_space_node(env->get_space_width(), 4983 env->get_fill_color(), this); 4984 res->freeze_space(); 4985 *widthp += res->width(); 4986 *spacep += res->nspaces(); 4987 return res; 4988 case charinfo::TRANSLATE_DUMMY: 4989 return new dummy_node(this); 4990 case charinfo::TRANSLATE_HYPHEN_INDICATOR: 4991 return add_discretionary_hyphen(); 4992 } 4993 charinfo *tem = ci->get_translation(); 4994 if (tem) 4995 ci = tem; 4996 macro *mac = ci->get_macro(); 4997 if (mac && ci->is_normal()) { 4998 res = make_composite_node(ci, env); 4999 if (res) { 5000 res->next = this; 5001 *widthp += res->width(); 5002 if (glyph_comp_np) 5003 *glyph_comp_np = res; 5004 } 5005 else { 5006 if (glyph_comp_np) 5007 *glyph_comp_np = res; 5008 return this; 5009 } 5010 } 5011 else { 5012 node *gn = make_glyph_node(ci, env); 5013 if (gn == 0) 5014 return this; 5015 else { 5016 hunits old_width = width(); 5017 node *p = gn->merge_self(this); 5018 if (p == 0) { 5019 *widthp += gn->width(); 5020 gn->next = this; 5021 res = gn; 5022 } 5023 else { 5024 *widthp += p->width() - old_width; 5025 res = p; 5026 } 5027 if (glyph_comp_np) 5028 *glyph_comp_np = res; 5029 } 5030 } 5031 int break_code = 0; 5032 if (ci->can_break_before()) 5033 break_code = 1; 5034 if (ci->can_break_after()) 5035 break_code |= 2; 5036 if (break_code) { 5037 node *next1 = res->next; 5038 res->next = 0; 5039 res = new break_char_node(res, break_code, env->get_fill_color(), next1); 5040 } 5041 return res; 5042 } 5043 5044 #ifdef __GNUG__ 5045 inline 5046 #endif 5047 int same_node(node *n1, node *n2) 5048 { 5049 if (n1 != 0) { 5050 if (n2 != 0) 5051 return n1->type() == n2->type() && n1->same(n2); 5052 else 5053 return 0; 5054 } 5055 else 5056 return n2 == 0; 5057 } 5058 5059 int same_node_list(node *n1, node *n2) 5060 { 5061 while (n1 && n2) { 5062 if (n1->type() != n2->type() || !n1->same(n2)) 5063 return 0; 5064 n1 = n1->next; 5065 n2 = n2->next; 5066 } 5067 return !n1 && !n2; 5068 } 5069 5070 int extra_size_node::same(node *nd) 5071 { 5072 return n == ((extra_size_node *)nd)->n; 5073 } 5074 5075 const char *extra_size_node::type() 5076 { 5077 return "extra_size_node"; 5078 } 5079 5080 int extra_size_node::force_tprint() 5081 { 5082 return 0; 5083 } 5084 5085 int extra_size_node::is_tag() 5086 { 5087 return 0; 5088 } 5089 5090 int vertical_size_node::same(node *nd) 5091 { 5092 return n == ((vertical_size_node *)nd)->n; 5093 } 5094 5095 const char *vertical_size_node::type() 5096 { 5097 return "vertical_size_node"; 5098 } 5099 5100 int vertical_size_node::set_unformat_flag() 5101 { 5102 return 0; 5103 } 5104 5105 int vertical_size_node::force_tprint() 5106 { 5107 return 0; 5108 } 5109 5110 int vertical_size_node::is_tag() 5111 { 5112 return 0; 5113 } 5114 5115 int hmotion_node::same(node *nd) 5116 { 5117 return n == ((hmotion_node *)nd)->n 5118 && col == ((hmotion_node *)nd)->col; 5119 } 5120 5121 const char *hmotion_node::type() 5122 { 5123 return "hmotion_node"; 5124 } 5125 5126 int hmotion_node::set_unformat_flag() 5127 { 5128 unformat = 1; 5129 return 1; 5130 } 5131 5132 int hmotion_node::force_tprint() 5133 { 5134 return 0; 5135 } 5136 5137 int hmotion_node::is_tag() 5138 { 5139 return 0; 5140 } 5141 5142 node *hmotion_node::add_self(node *nd, hyphen_list **p) 5143 { 5144 next = nd; 5145 hyphen_list *pp = *p; 5146 *p = (*p)->next; 5147 delete pp; 5148 return this; 5149 } 5150 5151 hyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail, int *) 5152 { 5153 return new hyphen_list(0, tail); 5154 } 5155 5156 int space_char_hmotion_node::same(node *nd) 5157 { 5158 return n == ((space_char_hmotion_node *)nd)->n 5159 && col == ((space_char_hmotion_node *)nd)->col; 5160 } 5161 5162 const char *space_char_hmotion_node::type() 5163 { 5164 return "space_char_hmotion_node"; 5165 } 5166 5167 int space_char_hmotion_node::force_tprint() 5168 { 5169 return 0; 5170 } 5171 5172 int space_char_hmotion_node::is_tag() 5173 { 5174 return 0; 5175 } 5176 5177 node *space_char_hmotion_node::add_self(node *nd, hyphen_list **p) 5178 { 5179 next = nd; 5180 hyphen_list *pp = *p; 5181 *p = (*p)->next; 5182 delete pp; 5183 return this; 5184 } 5185 5186 hyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail, 5187 int *) 5188 { 5189 return new hyphen_list(0, tail); 5190 } 5191 5192 int vmotion_node::same(node *nd) 5193 { 5194 return n == ((vmotion_node *)nd)->n 5195 && col == ((vmotion_node *)nd)->col; 5196 } 5197 5198 const char *vmotion_node::type() 5199 { 5200 return "vmotion_node"; 5201 } 5202 5203 int vmotion_node::force_tprint() 5204 { 5205 return 0; 5206 } 5207 5208 int vmotion_node::is_tag() 5209 { 5210 return 0; 5211 } 5212 5213 int hline_node::same(node *nd) 5214 { 5215 return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n); 5216 } 5217 5218 const char *hline_node::type() 5219 { 5220 return "hline_node"; 5221 } 5222 5223 int hline_node::force_tprint() 5224 { 5225 return 0; 5226 } 5227 5228 int hline_node::is_tag() 5229 { 5230 return 0; 5231 } 5232 5233 int vline_node::same(node *nd) 5234 { 5235 return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n); 5236 } 5237 5238 const char *vline_node::type() 5239 { 5240 return "vline_node"; 5241 } 5242 5243 int vline_node::force_tprint() 5244 { 5245 return 0; 5246 } 5247 5248 int vline_node::is_tag() 5249 { 5250 return 0; 5251 } 5252 5253 int dummy_node::same(node * /*nd*/) 5254 { 5255 return 1; 5256 } 5257 5258 const char *dummy_node::type() 5259 { 5260 return "dummy_node"; 5261 } 5262 5263 int dummy_node::force_tprint() 5264 { 5265 return 0; 5266 } 5267 5268 int dummy_node::is_tag() 5269 { 5270 return 0; 5271 } 5272 5273 int transparent_dummy_node::same(node * /*nd*/) 5274 { 5275 return 1; 5276 } 5277 5278 const char *transparent_dummy_node::type() 5279 { 5280 return "transparent_dummy_node"; 5281 } 5282 5283 int transparent_dummy_node::force_tprint() 5284 { 5285 return 0; 5286 } 5287 5288 int transparent_dummy_node::is_tag() 5289 { 5290 return 0; 5291 } 5292 5293 int transparent_dummy_node::ends_sentence() 5294 { 5295 return 2; 5296 } 5297 5298 int zero_width_node::same(node *nd) 5299 { 5300 return same_node_list(n, ((zero_width_node *)nd)->n); 5301 } 5302 5303 const char *zero_width_node::type() 5304 { 5305 return "zero_width_node"; 5306 } 5307 5308 int zero_width_node::force_tprint() 5309 { 5310 return 0; 5311 } 5312 5313 int zero_width_node::is_tag() 5314 { 5315 return 0; 5316 } 5317 5318 int italic_corrected_node::same(node *nd) 5319 { 5320 return (x == ((italic_corrected_node *)nd)->x 5321 && same_node(n, ((italic_corrected_node *)nd)->n)); 5322 } 5323 5324 const char *italic_corrected_node::type() 5325 { 5326 return "italic_corrected_node"; 5327 } 5328 5329 int italic_corrected_node::force_tprint() 5330 { 5331 return 0; 5332 } 5333 5334 int italic_corrected_node::is_tag() 5335 { 5336 return 0; 5337 } 5338 5339 left_italic_corrected_node::left_italic_corrected_node(node *xx) 5340 : node(xx), n(0) 5341 { 5342 } 5343 5344 left_italic_corrected_node::left_italic_corrected_node(statem *s, int pop, 5345 node *xx) 5346 : node(xx, s, pop), n(0) 5347 { 5348 } 5349 5350 left_italic_corrected_node::~left_italic_corrected_node() 5351 { 5352 delete n; 5353 } 5354 5355 node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn) 5356 { 5357 if (n == 0) { 5358 hunits lic = gn->left_italic_correction(); 5359 if (!lic.is_zero()) { 5360 x = lic; 5361 n = gn; 5362 return this; 5363 } 5364 } 5365 else { 5366 node *nd = n->merge_glyph_node(gn); 5367 if (nd) { 5368 n = nd; 5369 x = n->left_italic_correction(); 5370 return this; 5371 } 5372 } 5373 return 0; 5374 } 5375 5376 node *left_italic_corrected_node::copy() 5377 { 5378 left_italic_corrected_node *nd = 5379 new left_italic_corrected_node(state, div_nest_level); 5380 if (n) { 5381 nd->n = n->copy(); 5382 nd->x = x; 5383 } 5384 return nd; 5385 } 5386 5387 void left_italic_corrected_node::tprint(troff_output_file *out) 5388 { 5389 if (n) { 5390 out->right(x); 5391 n->tprint(out); 5392 } 5393 } 5394 5395 const char *left_italic_corrected_node::type() 5396 { 5397 return "left_italic_corrected_node"; 5398 } 5399 5400 int left_italic_corrected_node::force_tprint() 5401 { 5402 return 0; 5403 } 5404 5405 int left_italic_corrected_node::is_tag() 5406 { 5407 return 0; 5408 } 5409 5410 int left_italic_corrected_node::same(node *nd) 5411 { 5412 return (x == ((left_italic_corrected_node *)nd)->x 5413 && same_node(n, ((left_italic_corrected_node *)nd)->n)); 5414 } 5415 5416 void left_italic_corrected_node::ascii_print(ascii_output_file *out) 5417 { 5418 if (n) 5419 n->ascii_print(out); 5420 } 5421 5422 hunits left_italic_corrected_node::width() 5423 { 5424 return n ? n->width() + x : H0; 5425 } 5426 5427 void left_italic_corrected_node::vertical_extent(vunits *minimum, 5428 vunits *maximum) 5429 { 5430 if (n) 5431 n->vertical_extent(minimum, maximum); 5432 else 5433 node::vertical_extent(minimum, maximum); 5434 } 5435 5436 hunits left_italic_corrected_node::skew() 5437 { 5438 return n ? n->skew() + x/2 : H0; 5439 } 5440 5441 hunits left_italic_corrected_node::subscript_correction() 5442 { 5443 return n ? n->subscript_correction() : H0; 5444 } 5445 5446 hunits left_italic_corrected_node::italic_correction() 5447 { 5448 return n ? n->italic_correction() : H0; 5449 } 5450 5451 int left_italic_corrected_node::ends_sentence() 5452 { 5453 return n ? n->ends_sentence() : 0; 5454 } 5455 5456 int left_italic_corrected_node::overlaps_horizontally() 5457 { 5458 return n ? n->overlaps_horizontally() : 0; 5459 } 5460 5461 int left_italic_corrected_node::overlaps_vertically() 5462 { 5463 return n ? n->overlaps_vertically() : 0; 5464 } 5465 5466 node *left_italic_corrected_node::last_char_node() 5467 { 5468 return n ? n->last_char_node() : 0; 5469 } 5470 5471 tfont *left_italic_corrected_node::get_tfont() 5472 { 5473 return n ? n->get_tfont() : 0; 5474 } 5475 5476 hyphenation_type left_italic_corrected_node::get_hyphenation_type() 5477 { 5478 if (n) 5479 return n->get_hyphenation_type(); 5480 else 5481 return HYPHEN_MIDDLE; 5482 } 5483 5484 hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail, 5485 int *count) 5486 { 5487 return n ? n->get_hyphen_list(tail, count) : tail; 5488 } 5489 5490 node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p) 5491 { 5492 if (n) { 5493 nd = new left_italic_corrected_node(state, div_nest_level, nd); 5494 nd = n->add_self(nd, p); 5495 n = 0; 5496 delete this; 5497 } 5498 return nd; 5499 } 5500 5501 int left_italic_corrected_node::character_type() 5502 { 5503 return n ? n->character_type() : 0; 5504 } 5505 5506 int overstrike_node::same(node *nd) 5507 { 5508 return same_node_list(list, ((overstrike_node *)nd)->list); 5509 } 5510 5511 const char *overstrike_node::type() 5512 { 5513 return "overstrike_node"; 5514 } 5515 5516 int overstrike_node::force_tprint() 5517 { 5518 return 0; 5519 } 5520 5521 int overstrike_node::is_tag() 5522 { 5523 return 0; 5524 } 5525 5526 node *overstrike_node::add_self(node *n, hyphen_list **p) 5527 { 5528 next = n; 5529 hyphen_list *pp = *p; 5530 *p = (*p)->next; 5531 delete pp; 5532 return this; 5533 } 5534 5535 hyphen_list *overstrike_node::get_hyphen_list(hyphen_list *tail, int *) 5536 { 5537 return new hyphen_list(0, tail); 5538 } 5539 5540 int bracket_node::same(node *nd) 5541 { 5542 return same_node_list(list, ((bracket_node *)nd)->list); 5543 } 5544 5545 const char *bracket_node::type() 5546 { 5547 return "bracket_node"; 5548 } 5549 5550 int bracket_node::force_tprint() 5551 { 5552 return 0; 5553 } 5554 5555 int bracket_node::is_tag() 5556 { 5557 return 0; 5558 } 5559 5560 int composite_node::same(node *nd) 5561 { 5562 return ci == ((composite_node *)nd)->ci 5563 && same_node_list(n, ((composite_node *)nd)->n); 5564 } 5565 5566 const char *composite_node::type() 5567 { 5568 return "composite_node"; 5569 } 5570 5571 int composite_node::force_tprint() 5572 { 5573 return 0; 5574 } 5575 5576 int composite_node::is_tag() 5577 { 5578 return 0; 5579 } 5580 5581 int glyph_node::same(node *nd) 5582 { 5583 return ci == ((glyph_node *)nd)->ci 5584 && tf == ((glyph_node *)nd)->tf 5585 && gcol == ((glyph_node *)nd)->gcol 5586 && fcol == ((glyph_node *)nd)->fcol; 5587 } 5588 5589 const char *glyph_node::type() 5590 { 5591 return "glyph_node"; 5592 } 5593 5594 int glyph_node::force_tprint() 5595 { 5596 return 0; 5597 } 5598 5599 int glyph_node::is_tag() 5600 { 5601 return 0; 5602 } 5603 5604 int ligature_node::same(node *nd) 5605 { 5606 return (same_node(n1, ((ligature_node *)nd)->n1) 5607 && same_node(n2, ((ligature_node *)nd)->n2) 5608 && glyph_node::same(nd)); 5609 } 5610 5611 const char *ligature_node::type() 5612 { 5613 return "ligature_node"; 5614 } 5615 5616 int ligature_node::force_tprint() 5617 { 5618 return 0; 5619 } 5620 5621 int ligature_node::is_tag() 5622 { 5623 return 0; 5624 } 5625 5626 int kern_pair_node::same(node *nd) 5627 { 5628 return (amount == ((kern_pair_node *)nd)->amount 5629 && same_node(n1, ((kern_pair_node *)nd)->n1) 5630 && same_node(n2, ((kern_pair_node *)nd)->n2)); 5631 } 5632 5633 const char *kern_pair_node::type() 5634 { 5635 return "kern_pair_node"; 5636 } 5637 5638 int kern_pair_node::force_tprint() 5639 { 5640 return 0; 5641 } 5642 5643 int kern_pair_node::is_tag() 5644 { 5645 return 0; 5646 } 5647 5648 int dbreak_node::same(node *nd) 5649 { 5650 return (same_node_list(none, ((dbreak_node *)nd)->none) 5651 && same_node_list(pre, ((dbreak_node *)nd)->pre) 5652 && same_node_list(post, ((dbreak_node *)nd)->post)); 5653 } 5654 5655 const char *dbreak_node::type() 5656 { 5657 return "dbreak_node"; 5658 } 5659 5660 int dbreak_node::force_tprint() 5661 { 5662 return 0; 5663 } 5664 5665 int dbreak_node::is_tag() 5666 { 5667 return 0; 5668 } 5669 5670 int break_char_node::same(node *nd) 5671 { 5672 return break_code == ((break_char_node *)nd)->break_code 5673 && col == ((break_char_node *)nd)->col 5674 && same_node(ch, ((break_char_node *)nd)->ch); 5675 } 5676 5677 const char *break_char_node::type() 5678 { 5679 return "break_char_node"; 5680 } 5681 5682 int break_char_node::force_tprint() 5683 { 5684 return 0; 5685 } 5686 5687 int break_char_node::is_tag() 5688 { 5689 return 0; 5690 } 5691 5692 int line_start_node::same(node * /*nd*/) 5693 { 5694 return 1; 5695 } 5696 5697 const char *line_start_node::type() 5698 { 5699 return "line_start_node"; 5700 } 5701 5702 int line_start_node::force_tprint() 5703 { 5704 return 0; 5705 } 5706 5707 int line_start_node::is_tag() 5708 { 5709 return 0; 5710 } 5711 5712 int space_node::same(node *nd) 5713 { 5714 return n == ((space_node *)nd)->n 5715 && set == ((space_node *)nd)->set 5716 && col == ((space_node *)nd)->col; 5717 } 5718 5719 const char *space_node::type() 5720 { 5721 return "space_node"; 5722 } 5723 5724 int word_space_node::same(node *nd) 5725 { 5726 return n == ((word_space_node *)nd)->n 5727 && set == ((word_space_node *)nd)->set 5728 && col == ((word_space_node *)nd)->col; 5729 } 5730 5731 const char *word_space_node::type() 5732 { 5733 return "word_space_node"; 5734 } 5735 5736 int word_space_node::force_tprint() 5737 { 5738 return 0; 5739 } 5740 5741 int word_space_node::is_tag() 5742 { 5743 return 0; 5744 } 5745 5746 void unbreakable_space_node::tprint(troff_output_file *out) 5747 { 5748 out->fill_color(col); 5749 if (is_html) { 5750 // we emit the space width as a negative glyph index 5751 out->flush_tbuf(); 5752 out->do_motion(); 5753 out->put('N'); 5754 out->put(-n.to_units()); 5755 out->put('\n'); 5756 } 5757 out->right(n); 5758 } 5759 5760 int unbreakable_space_node::same(node *nd) 5761 { 5762 return n == ((unbreakable_space_node *)nd)->n 5763 && set == ((unbreakable_space_node *)nd)->set 5764 && col == ((unbreakable_space_node *)nd)->col; 5765 } 5766 5767 const char *unbreakable_space_node::type() 5768 { 5769 return "unbreakable_space_node"; 5770 } 5771 5772 node *unbreakable_space_node::add_self(node *nd, hyphen_list **p) 5773 { 5774 next = nd; 5775 hyphen_list *pp = *p; 5776 *p = (*p)->next; 5777 delete pp; 5778 return this; 5779 } 5780 5781 hyphen_list *unbreakable_space_node::get_hyphen_list(hyphen_list *tail, int *) 5782 { 5783 return new hyphen_list(0, tail); 5784 } 5785 5786 int diverted_space_node::same(node *nd) 5787 { 5788 return n == ((diverted_space_node *)nd)->n; 5789 } 5790 5791 const char *diverted_space_node::type() 5792 { 5793 return "diverted_space_node"; 5794 } 5795 5796 int diverted_space_node::force_tprint() 5797 { 5798 return 0; 5799 } 5800 5801 int diverted_space_node::is_tag() 5802 { 5803 return 0; 5804 } 5805 5806 int diverted_copy_file_node::same(node *nd) 5807 { 5808 return filename == ((diverted_copy_file_node *)nd)->filename; 5809 } 5810 5811 const char *diverted_copy_file_node::type() 5812 { 5813 return "diverted_copy_file_node"; 5814 } 5815 5816 int diverted_copy_file_node::force_tprint() 5817 { 5818 return 0; 5819 } 5820 5821 int diverted_copy_file_node::is_tag() 5822 { 5823 return 0; 5824 } 5825 5826 // Grow the font_table so that its size is > n. 5827 5828 static void grow_font_table(int n) 5829 { 5830 assert(n >= font_table_size); 5831 font_info **old_font_table = font_table; 5832 int old_font_table_size = font_table_size; 5833 font_table_size = font_table_size ? (font_table_size*3)/2 : 10; 5834 if (font_table_size <= n) 5835 font_table_size = n + 10; 5836 font_table = new font_info *[font_table_size]; 5837 if (old_font_table_size) 5838 memcpy(font_table, old_font_table, 5839 old_font_table_size*sizeof(font_info *)); 5840 a_delete old_font_table; 5841 for (int i = old_font_table_size; i < font_table_size; i++) 5842 font_table[i] = 0; 5843 } 5844 5845 dictionary font_translation_dictionary(17); 5846 5847 static symbol get_font_translation(symbol nm) 5848 { 5849 void *p = font_translation_dictionary.lookup(nm); 5850 return p ? symbol((char *)p) : nm; 5851 } 5852 5853 dictionary font_dictionary(50); 5854 5855 static int mount_font_no_translate(int n, symbol name, symbol external_name, 5856 int check_only = 0) 5857 { 5858 assert(n >= 0); 5859 // We store the address of this char in font_dictionary to indicate 5860 // that we've previously tried to mount the font and failed. 5861 static char a_char; 5862 font *fm = 0; 5863 void *p = font_dictionary.lookup(external_name); 5864 if (p == 0) { 5865 int not_found; 5866 fm = font::load_font(external_name.contents(), ¬_found, check_only); 5867 if (check_only) 5868 return fm != 0; 5869 if (!fm) { 5870 if (not_found) 5871 warning(WARN_FONT, "can't find font `%1'", external_name.contents()); 5872 (void)font_dictionary.lookup(external_name, &a_char); 5873 return 0; 5874 } 5875 (void)font_dictionary.lookup(name, fm); 5876 } 5877 else if (p == &a_char) { 5878 #if 0 5879 error("invalid font `%1'", external_name.contents()); 5880 #endif 5881 return 0; 5882 } 5883 else 5884 fm = (font*)p; 5885 if (check_only) 5886 return 1; 5887 if (n >= font_table_size) { 5888 if (n - font_table_size > 1000) { 5889 error("font position too much larger than first unused position"); 5890 return 0; 5891 } 5892 grow_font_table(n); 5893 } 5894 else if (font_table[n] != 0) 5895 delete font_table[n]; 5896 font_table[n] = new font_info(name, n, external_name, fm); 5897 font_family::invalidate_fontno(n); 5898 return 1; 5899 } 5900 5901 int mount_font(int n, symbol name, symbol external_name) 5902 { 5903 assert(n >= 0); 5904 name = get_font_translation(name); 5905 if (external_name.is_null()) 5906 external_name = name; 5907 else 5908 external_name = get_font_translation(external_name); 5909 return mount_font_no_translate(n, name, external_name); 5910 } 5911 5912 int check_font(symbol fam, symbol name) 5913 { 5914 if (check_style(name)) 5915 name = concat(fam, name); 5916 return mount_font_no_translate(0, name, name, 1); 5917 } 5918 5919 int check_style(symbol s) 5920 { 5921 int i = symbol_fontno(s); 5922 return i < 0 ? 0 : font_table[i]->is_style(); 5923 } 5924 5925 void mount_style(int n, symbol name) 5926 { 5927 assert(n >= 0); 5928 if (n >= font_table_size) { 5929 if (n - font_table_size > 1000) { 5930 error("font position too much larger than first unused position"); 5931 return; 5932 } 5933 grow_font_table(n); 5934 } 5935 else if (font_table[n] != 0) 5936 delete font_table[n]; 5937 font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0); 5938 font_family::invalidate_fontno(n); 5939 } 5940 5941 /* global functions */ 5942 5943 void font_translate() 5944 { 5945 symbol from = get_name(1); 5946 if (!from.is_null()) { 5947 symbol to = get_name(); 5948 if (to.is_null() || from == to) 5949 font_translation_dictionary.remove(from); 5950 else 5951 (void)font_translation_dictionary.lookup(from, (void *)to.contents()); 5952 } 5953 skip_line(); 5954 } 5955 5956 void font_position() 5957 { 5958 int n; 5959 if (get_integer(&n)) { 5960 if (n < 0) 5961 error("negative font position"); 5962 else { 5963 symbol internal_name = get_name(1); 5964 if (!internal_name.is_null()) { 5965 symbol external_name = get_long_name(); 5966 mount_font(n, internal_name, external_name); // ignore error 5967 } 5968 } 5969 } 5970 skip_line(); 5971 } 5972 5973 font_family::font_family(symbol s) 5974 : map_size(10), nm(s) 5975 { 5976 map = new int[map_size]; 5977 for (int i = 0; i < map_size; i++) 5978 map[i] = -1; 5979 } 5980 5981 font_family::~font_family() 5982 { 5983 a_delete map; 5984 } 5985 5986 int font_family::make_definite(int i) 5987 { 5988 if (i >= 0) { 5989 if (i < map_size && map[i] >= 0) 5990 return map[i]; 5991 else { 5992 if (i < font_table_size && font_table[i] != 0) { 5993 if (i >= map_size) { 5994 int old_map_size = map_size; 5995 int *old_map = map; 5996 map_size *= 3; 5997 map_size /= 2; 5998 if (i >= map_size) 5999 map_size = i + 10; 6000 map = new int[map_size]; 6001 memcpy(map, old_map, old_map_size*sizeof(int)); 6002 a_delete old_map; 6003 for (int j = old_map_size; j < map_size; j++) 6004 map[j] = -1; 6005 } 6006 if (font_table[i]->is_style()) { 6007 symbol sty = font_table[i]->get_name(); 6008 symbol f = concat(nm, sty); 6009 int n; 6010 // don't use symbol_fontno, because that might return a style 6011 // and because we don't want to translate the name 6012 for (n = 0; n < font_table_size; n++) 6013 if (font_table[n] != 0 && font_table[n]->is_named(f) 6014 && !font_table[n]->is_style()) 6015 break; 6016 if (n >= font_table_size) { 6017 n = next_available_font_position(); 6018 if (!mount_font_no_translate(n, f, f)) 6019 return -1; 6020 } 6021 return map[i] = n; 6022 } 6023 else 6024 return map[i] = i; 6025 } 6026 else 6027 return -1; 6028 } 6029 } 6030 else 6031 return -1; 6032 } 6033 6034 dictionary family_dictionary(5); 6035 6036 font_family *lookup_family(symbol nm) 6037 { 6038 font_family *f = (font_family *)family_dictionary.lookup(nm); 6039 if (!f) { 6040 f = new font_family(nm); 6041 (void)family_dictionary.lookup(nm, f); 6042 } 6043 return f; 6044 } 6045 6046 void font_family::invalidate_fontno(int n) 6047 { 6048 assert(n >= 0 && n < font_table_size); 6049 dictionary_iterator iter(family_dictionary); 6050 symbol nam; 6051 font_family *fam; 6052 while (iter.get(&nam, (void **)&fam)) { 6053 int mapsize = fam->map_size; 6054 if (n < mapsize) 6055 fam->map[n] = -1; 6056 for (int i = 0; i < mapsize; i++) 6057 if (fam->map[i] == n) 6058 fam->map[i] = -1; 6059 } 6060 } 6061 6062 void style() 6063 { 6064 int n; 6065 if (get_integer(&n)) { 6066 if (n < 0) 6067 error("negative font position"); 6068 else { 6069 symbol internal_name = get_name(1); 6070 if (!internal_name.is_null()) 6071 mount_style(n, internal_name); 6072 } 6073 } 6074 skip_line(); 6075 } 6076 6077 static int get_fontno() 6078 { 6079 int n; 6080 tok.skip(); 6081 if (tok.delimiter()) { 6082 symbol s = get_name(1); 6083 if (!s.is_null()) { 6084 n = symbol_fontno(s); 6085 if (n < 0) { 6086 n = next_available_font_position(); 6087 if (!mount_font(n, s)) 6088 return -1; 6089 } 6090 return curenv->get_family()->make_definite(n); 6091 } 6092 } 6093 else if (get_integer(&n)) { 6094 if (n < 0 || n >= font_table_size || font_table[n] == 0) 6095 error("bad font number"); 6096 else 6097 return curenv->get_family()->make_definite(n); 6098 } 6099 return -1; 6100 } 6101 6102 static int underline_fontno = 2; 6103 6104 void underline_font() 6105 { 6106 int n = get_fontno(); 6107 if (n >= 0) 6108 underline_fontno = n; 6109 skip_line(); 6110 } 6111 6112 int get_underline_fontno() 6113 { 6114 return underline_fontno; 6115 } 6116 6117 void define_font_special_character() 6118 { 6119 int n = get_fontno(); 6120 if (n < 0) { 6121 skip_line(); 6122 return; 6123 } 6124 symbol f = font_table[n]->get_name(); 6125 do_define_character(CHAR_FONT_SPECIAL, f.contents()); 6126 } 6127 6128 void remove_font_special_character() 6129 { 6130 int n = get_fontno(); 6131 if (n < 0) { 6132 skip_line(); 6133 return; 6134 } 6135 symbol f = font_table[n]->get_name(); 6136 while (!tok.newline() && !tok.eof()) { 6137 if (!tok.space() && !tok.tab()) { 6138 charinfo *s = tok.get_char(1); 6139 string gl(f.contents()); 6140 gl += ' '; 6141 gl += s->nm.contents(); 6142 gl += '\0'; 6143 charinfo *ci = get_charinfo(symbol(gl.contents())); 6144 if (!ci) 6145 break; 6146 macro *m = ci->set_macro(0); 6147 if (m) 6148 delete m; 6149 } 6150 tok.next(); 6151 } 6152 skip_line(); 6153 } 6154 6155 static void read_special_fonts(special_font_list **sp) 6156 { 6157 special_font_list *s = *sp; 6158 *sp = 0; 6159 while (s != 0) { 6160 special_font_list *tem = s; 6161 s = s->next; 6162 delete tem; 6163 } 6164 special_font_list **p = sp; 6165 while (has_arg()) { 6166 int i = get_fontno(); 6167 if (i >= 0) { 6168 special_font_list *tem = new special_font_list; 6169 tem->n = i; 6170 tem->next = 0; 6171 *p = tem; 6172 p = &(tem->next); 6173 } 6174 } 6175 } 6176 6177 void font_special_request() 6178 { 6179 int n = get_fontno(); 6180 if (n >= 0) 6181 read_special_fonts(&font_table[n]->sf); 6182 skip_line(); 6183 } 6184 6185 void special_request() 6186 { 6187 read_special_fonts(&global_special_fonts); 6188 skip_line(); 6189 } 6190 6191 int next_available_font_position() 6192 { 6193 int i; 6194 for (i = 1; i < font_table_size && font_table[i] != 0; i++) 6195 ; 6196 return i; 6197 } 6198 6199 int symbol_fontno(symbol s) 6200 { 6201 s = get_font_translation(s); 6202 for (int i = 0; i < font_table_size; i++) 6203 if (font_table[i] != 0 && font_table[i]->is_named(s)) 6204 return i; 6205 return -1; 6206 } 6207 6208 int is_good_fontno(int n) 6209 { 6210 return n >= 0 && n < font_table_size && font_table[n] != 0; 6211 } 6212 6213 int get_bold_fontno(int n) 6214 { 6215 if (n >= 0 && n < font_table_size && font_table[n] != 0) { 6216 hunits offset; 6217 if (font_table[n]->get_bold(&offset)) 6218 return offset.to_units() + 1; 6219 else 6220 return 0; 6221 } 6222 else 6223 return 0; 6224 } 6225 6226 hunits env_digit_width(environment *env) 6227 { 6228 node *n = make_glyph_node(charset_table['0'], env); 6229 if (n) { 6230 hunits x = n->width(); 6231 delete n; 6232 return x; 6233 } 6234 else 6235 return H0; 6236 } 6237 6238 hunits env_space_width(environment *env) 6239 { 6240 int fn = env_definite_font(env); 6241 font_size fs = env->get_font_size(); 6242 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) 6243 return scale(fs.to_units()/3, env->get_space_size(), 12); 6244 else 6245 return font_table[fn]->get_space_width(fs, env->get_space_size()); 6246 } 6247 6248 hunits env_sentence_space_width(environment *env) 6249 { 6250 int fn = env_definite_font(env); 6251 font_size fs = env->get_font_size(); 6252 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) 6253 return scale(fs.to_units()/3, env->get_sentence_space_size(), 12); 6254 else 6255 return font_table[fn]->get_space_width(fs, env->get_sentence_space_size()); 6256 } 6257 6258 hunits env_half_narrow_space_width(environment *env) 6259 { 6260 int fn = env_definite_font(env); 6261 font_size fs = env->get_font_size(); 6262 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) 6263 return 0; 6264 else 6265 return font_table[fn]->get_half_narrow_space_width(fs); 6266 } 6267 6268 hunits env_narrow_space_width(environment *env) 6269 { 6270 int fn = env_definite_font(env); 6271 font_size fs = env->get_font_size(); 6272 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) 6273 return 0; 6274 else 6275 return font_table[fn]->get_narrow_space_width(fs); 6276 } 6277 6278 void bold_font() 6279 { 6280 int n = get_fontno(); 6281 if (n >= 0) { 6282 if (has_arg()) { 6283 if (tok.delimiter()) { 6284 int f = get_fontno(); 6285 if (f >= 0) { 6286 units offset; 6287 if (has_arg() && get_number(&offset, 'u') && offset >= 1) 6288 font_table[f]->set_conditional_bold(n, hunits(offset - 1)); 6289 else 6290 font_table[f]->conditional_unbold(n); 6291 } 6292 } 6293 else { 6294 units offset; 6295 if (get_number(&offset, 'u') && offset >= 1) 6296 font_table[n]->set_bold(hunits(offset - 1)); 6297 else 6298 font_table[n]->unbold(); 6299 } 6300 } 6301 else 6302 font_table[n]->unbold(); 6303 } 6304 skip_line(); 6305 } 6306 6307 track_kerning_function::track_kerning_function() : non_zero(0) 6308 { 6309 } 6310 6311 track_kerning_function::track_kerning_function(int min_s, hunits min_a, 6312 int max_s, hunits max_a) 6313 : non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s), 6314 max_amount(max_a) 6315 { 6316 } 6317 6318 int track_kerning_function::operator==(const track_kerning_function &tk) 6319 { 6320 if (non_zero) 6321 return (tk.non_zero 6322 && min_size == tk.min_size 6323 && min_amount == tk.min_amount 6324 && max_size == tk.max_size 6325 && max_amount == tk.max_amount); 6326 else 6327 return !tk.non_zero; 6328 } 6329 6330 int track_kerning_function::operator!=(const track_kerning_function &tk) 6331 { 6332 if (non_zero) 6333 return (!tk.non_zero 6334 || min_size != tk.min_size 6335 || min_amount != tk.min_amount 6336 || max_size != tk.max_size 6337 || max_amount != tk.max_amount); 6338 else 6339 return tk.non_zero; 6340 } 6341 6342 hunits track_kerning_function::compute(int size) 6343 { 6344 if (non_zero) { 6345 if (max_size <= min_size) 6346 return min_amount; 6347 else if (size <= min_size) 6348 return min_amount; 6349 else if (size >= max_size) 6350 return max_amount; 6351 else 6352 return (scale(max_amount, size - min_size, max_size - min_size) 6353 + scale(min_amount, max_size - size, max_size - min_size)); 6354 } 6355 else 6356 return H0; 6357 } 6358 6359 void track_kern() 6360 { 6361 int n = get_fontno(); 6362 if (n >= 0) { 6363 int min_s, max_s; 6364 hunits min_a, max_a; 6365 if (has_arg() 6366 && get_number(&min_s, 'z') 6367 && get_hunits(&min_a, 'p') 6368 && get_number(&max_s, 'z') 6369 && get_hunits(&max_a, 'p')) { 6370 track_kerning_function tk(min_s, min_a, max_s, max_a); 6371 font_table[n]->set_track_kern(tk); 6372 } 6373 else { 6374 track_kerning_function tk; 6375 font_table[n]->set_track_kern(tk); 6376 } 6377 } 6378 skip_line(); 6379 } 6380 6381 void constant_space() 6382 { 6383 int n = get_fontno(); 6384 if (n >= 0) { 6385 int x, y; 6386 if (!has_arg() || !get_integer(&x)) 6387 font_table[n]->set_constant_space(CONSTANT_SPACE_NONE); 6388 else { 6389 if (!has_arg() || !get_number(&y, 'z')) 6390 font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x); 6391 else 6392 font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE, 6393 scale(y*x, 6394 units_per_inch, 6395 36*72*sizescale)); 6396 } 6397 } 6398 skip_line(); 6399 } 6400 6401 void ligature() 6402 { 6403 int lig; 6404 if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2) 6405 global_ligature_mode = lig; 6406 else 6407 global_ligature_mode = 1; 6408 skip_line(); 6409 } 6410 6411 void kern_request() 6412 { 6413 int k; 6414 if (has_arg() && get_integer(&k)) 6415 global_kern_mode = k != 0; 6416 else 6417 global_kern_mode = 1; 6418 skip_line(); 6419 } 6420 6421 void set_soft_hyphen_char() 6422 { 6423 soft_hyphen_char = get_optional_char(); 6424 if (!soft_hyphen_char) 6425 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); 6426 skip_line(); 6427 } 6428 6429 void init_output() 6430 { 6431 if (suppress_output_flag) 6432 the_output = new suppress_output_file; 6433 else if (ascii_output_flag) 6434 the_output = new ascii_output_file; 6435 else 6436 the_output = new troff_output_file; 6437 } 6438 6439 class next_available_font_position_reg : public reg { 6440 public: 6441 const char *get_string(); 6442 }; 6443 6444 const char *next_available_font_position_reg::get_string() 6445 { 6446 return i_to_a(next_available_font_position()); 6447 } 6448 6449 class printing_reg : public reg { 6450 public: 6451 const char *get_string(); 6452 }; 6453 6454 const char *printing_reg::get_string() 6455 { 6456 if (the_output) 6457 return the_output->is_printing() ? "1" : "0"; 6458 else 6459 return "0"; 6460 } 6461 6462 void init_node_requests() 6463 { 6464 init_request("bd", bold_font); 6465 init_request("cs", constant_space); 6466 init_request("fp", font_position); 6467 init_request("fschar", define_font_special_character); 6468 init_request("fspecial", font_special_request); 6469 init_request("ftr", font_translate); 6470 init_request("kern", kern_request); 6471 init_request("lg", ligature); 6472 init_request("rfschar", remove_font_special_character); 6473 init_request("shc", set_soft_hyphen_char); 6474 init_request("special", special_request); 6475 init_request("sty", style); 6476 init_request("tkf", track_kern); 6477 init_request("uf", underline_font); 6478 number_reg_dictionary.define(".fp", new next_available_font_position_reg); 6479 number_reg_dictionary.define(".kern", 6480 new constant_int_reg(&global_kern_mode)); 6481 number_reg_dictionary.define(".lg", 6482 new constant_int_reg(&global_ligature_mode)); 6483 number_reg_dictionary.define(".P", new printing_reg); 6484 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); 6485 } 6486