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