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