home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / troff / node.cc < prev    next >
C/C++ Source or Header  |  1995-06-22  |  96KB  |  4,867 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  20.  
  21. #include "troff.h"
  22. #include "symbol.h"
  23. #include "dictionary.h"
  24. #include "hvunits.h"
  25. #include "env.h"
  26. #include "request.h"
  27. #include "node.h"
  28. #include "token.h"
  29. #include "charinfo.h"
  30. #include "font.h"
  31. #include "reg.h"
  32.  
  33. #define STORE_WIDTH 1
  34.  
  35. symbol HYPHEN_SYMBOL("hy");
  36.  
  37. // Character used when a hyphen is inserted at a line break.
  38. static charinfo *soft_hyphen_char;
  39.  
  40. enum constant_space_type { 
  41.   CONSTANT_SPACE_NONE,
  42.   CONSTANT_SPACE_RELATIVE,
  43.   CONSTANT_SPACE_ABSOLUTE
  44.   };
  45.  
  46. struct special_font_list {
  47.   int n;
  48.   special_font_list *next;
  49. };
  50.  
  51. special_font_list *global_special_fonts;
  52. static int global_ligature_mode = 1;
  53. static int global_kern_mode = 1;
  54.  
  55. class track_kerning_function {
  56.   int non_zero;
  57.   units min_size;
  58.   hunits min_amount;
  59.   units max_size;
  60.   hunits max_amount;
  61. public:
  62.   track_kerning_function();
  63.   track_kerning_function(units, hunits, units, hunits);
  64.   int operator==(const track_kerning_function &);
  65.   int operator!=(const track_kerning_function &);
  66.   hunits compute(int point_size);
  67. };
  68.  
  69. // embolden fontno when this is the current font
  70.  
  71. struct conditional_bold {
  72.   conditional_bold *next;
  73.   int fontno;
  74.   hunits offset;
  75.   conditional_bold(int, hunits, conditional_bold * = 0);
  76. };
  77.  
  78. struct tfont;
  79.  
  80. class font_info {
  81.   tfont *last_tfont;
  82.   int number;
  83.   font_size last_size;
  84.   int last_height;
  85.   int last_slant;
  86.   symbol internal_name;
  87.   symbol external_name;
  88.   font *fm;
  89.   char is_bold;
  90.   hunits bold_offset;
  91.   track_kerning_function track_kern;
  92.   constant_space_type is_constant_spaced;
  93.   units constant_space;
  94.   int last_ligature_mode;
  95.   int last_kern_mode;
  96.   conditional_bold *cond_bold_list;
  97.   void flush();
  98. public:
  99.   special_font_list *sf;
  100.   
  101.   font_info(symbol nm, int n, symbol enm, font *f);
  102.   int contains(charinfo *);
  103.   void set_bold(hunits);
  104.   void unbold();
  105.   void set_conditional_bold(int, hunits);
  106.   void conditional_unbold(int);
  107.   void set_track_kern(track_kerning_function &);
  108.   void set_constant_space(constant_space_type, units = 0);
  109.   int is_named(symbol);
  110.   symbol get_name();
  111.   tfont *get_tfont(font_size, int, int, int);
  112.   hunits get_space_width(font_size, int);
  113.   hunits get_narrow_space_width(font_size);
  114.   hunits get_half_narrow_space_width(font_size);
  115.   int get_bold(hunits *);
  116.   int is_special();
  117.   int is_style();
  118. };
  119.  
  120. class tfont_spec {
  121. protected:
  122.   symbol name;
  123.   int input_position;
  124.   font *fm;
  125.   font_size size;
  126.   char is_bold;
  127.   char is_constant_spaced;
  128.   int ligature_mode;
  129.   int kern_mode;
  130.   hunits bold_offset;
  131.   hunits track_kern;            // add this to the width
  132.   hunits constant_space_width;
  133.   int height;
  134.   int slant;
  135. public:
  136.   tfont_spec(symbol nm, int pos, font *, font_size, int, int);
  137.   tfont_spec(const tfont_spec &spec) { *this = spec; }
  138.   tfont_spec plain();
  139.   int operator==(const tfont_spec &);
  140.   friend tfont *font_info::get_tfont(font_size fs, int, int, int);
  141. };
  142.  
  143. class tfont : public tfont_spec {
  144.   static tfont *tfont_list;
  145.   tfont *next;
  146.   tfont *plain_version;
  147. public:
  148.   tfont(tfont_spec &);
  149.   int contains(charinfo *);
  150.   hunits get_width(charinfo *c);
  151.   int get_bold(hunits *);
  152.   int get_constant_space(hunits *);
  153.   hunits get_track_kern();
  154.   tfont *get_plain();
  155.   font_size get_size();
  156.   symbol get_name();
  157.   charinfo *get_lig(charinfo *c1, charinfo *c2);
  158.   int get_kern(charinfo *c1, charinfo *c2, hunits *res);
  159.   int get_input_position();
  160.   int get_character_type(charinfo *);
  161.   int get_height();
  162.   int get_slant();
  163.   vunits get_char_height(charinfo *);
  164.   vunits get_char_depth(charinfo *);
  165.   hunits get_char_skew(charinfo *);
  166.   hunits get_italic_correction(charinfo *);
  167.   hunits get_left_italic_correction(charinfo *);
  168.   hunits get_subscript_correction(charinfo *);
  169.   friend tfont *make_tfont(tfont_spec &);
  170. };
  171.  
  172. inline int env_definite_font(environment *env)
  173. {
  174.   return env->get_family()->make_definite(env->get_font());
  175. }
  176.  
  177. /* font_info functions */
  178.  
  179. static font_info **font_table = 0;
  180. static int font_table_size = 0;
  181.  
  182. font_info::font_info(symbol nm, int n, symbol enm, font *f)
  183. : internal_name(nm), external_name(enm), fm(f), number(n),
  184.   is_constant_spaced(CONSTANT_SPACE_NONE),
  185.   sf(0), is_bold(0), cond_bold_list(0),
  186.   last_ligature_mode(1), last_kern_mode(1),
  187.   last_tfont(0), last_size(0)
  188. {
  189. }
  190.  
  191. inline int font_info::contains(charinfo *ci)
  192. {
  193.   return fm != 0 && fm->contains(ci->get_index());
  194. }
  195.  
  196. inline int font_info::is_special()
  197. {
  198.   return fm != 0 && fm->is_special();
  199. }
  200.  
  201. inline int font_info::is_style()
  202. {
  203.   return fm == 0;
  204. }
  205.  
  206. // this is the current_font, fontno is where we found the character,
  207. // presumably a special font
  208.  
  209. tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
  210. {
  211.   if (last_tfont == 0 || fs != last_size
  212.       || height != last_height || slant != last_slant
  213.       || global_ligature_mode != last_ligature_mode
  214.       || global_kern_mode != last_kern_mode
  215.       || fontno != number) {
  216.     font_info *f = font_table[fontno];
  217.     tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
  218.     for (conditional_bold *p = cond_bold_list; p; p = p->next)
  219.       if (p->fontno == fontno) {
  220.         spec.is_bold = 1;
  221.         spec.bold_offset = p->offset;
  222.         break;
  223.       }
  224.     if (!spec.is_bold && is_bold) {
  225.       spec.is_bold = 1;
  226.       spec.bold_offset = bold_offset;
  227.     }
  228.     spec.track_kern = track_kern.compute(fs.to_scaled_points());
  229.     spec.ligature_mode = global_ligature_mode;
  230.     spec.kern_mode = global_kern_mode;
  231.     switch (is_constant_spaced) {
  232.     case CONSTANT_SPACE_NONE:
  233.       break;
  234.     case CONSTANT_SPACE_ABSOLUTE:
  235.       spec.is_constant_spaced = 1;
  236.       spec.constant_space_width = constant_space;
  237.       break;
  238.     case CONSTANT_SPACE_RELATIVE:
  239.       spec.is_constant_spaced = 1;
  240.       spec.constant_space_width
  241.         = scale(constant_space*fs.to_scaled_points(),
  242.             units_per_inch,
  243.             36*72*sizescale);
  244.       break;
  245.     default:
  246.       assert(0);
  247.     }
  248.     if (fontno != number)
  249.       return make_tfont(spec);
  250.     last_tfont = make_tfont(spec);
  251.     last_size = fs;
  252.     last_height = height;
  253.     last_slant = slant;
  254.     last_ligature_mode = global_ligature_mode;
  255.     last_kern_mode = global_kern_mode;
  256.       }
  257.   return last_tfont;
  258. }
  259.  
  260. int font_info::get_bold(hunits *res)
  261. {
  262.   if (is_bold) {
  263.     *res = bold_offset;
  264.     return 1;
  265.   }
  266.   else
  267.     return 0;
  268. }
  269.  
  270. void font_info::unbold()
  271. {
  272.   if (is_bold) {
  273.     is_bold = 0;
  274.     flush();
  275.   }
  276. }
  277.  
  278. void font_info::set_bold(hunits offset)
  279. {
  280.   if (!is_bold || offset != bold_offset) {
  281.     is_bold = 1;
  282.     bold_offset = offset;
  283.     flush();
  284.   }
  285. }
  286.  
  287. void font_info::set_conditional_bold(int fontno, hunits offset)
  288. {
  289.   for (conditional_bold *p = cond_bold_list; p; p = p->next)
  290.     if (p->fontno == fontno) {
  291.       if (offset != p->offset) {
  292.     p->offset = offset;
  293.     flush();
  294.       }
  295.       return;
  296.     }
  297.   cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
  298. }
  299.  
  300. conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
  301.      : fontno(f), offset(h), next(x)
  302. {
  303. }
  304.  
  305. void font_info::conditional_unbold(int fontno)
  306. {
  307.   for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
  308.     if ((*p)->fontno == fontno) {
  309.       conditional_bold *tem = *p;
  310.       *p = (*p)->next;
  311.       delete tem;
  312.       flush();
  313.       return;
  314.     }
  315. }
  316.                  
  317. void font_info::set_constant_space(constant_space_type type, units x)
  318. {
  319.   if (type != is_constant_spaced
  320.       || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
  321.     flush();
  322.     is_constant_spaced = type;
  323.     constant_space = x;
  324.       }
  325. }
  326.  
  327. void font_info::set_track_kern(track_kerning_function  &tk)
  328. {
  329.   if (track_kern != tk) {
  330.     track_kern = tk;
  331.     flush();
  332.   }
  333. }
  334.  
  335. void font_info::flush()
  336. {
  337.   last_tfont = 0;
  338. }
  339.  
  340. int font_info::is_named(symbol s)
  341. {
  342.   return internal_name == s;
  343. }
  344.  
  345. symbol font_info::get_name()
  346. {
  347.   return internal_name;
  348. }
  349.  
  350. hunits font_info::get_space_width(font_size fs, int space_size)
  351. {
  352.   if (is_constant_spaced == CONSTANT_SPACE_NONE)
  353.     return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
  354.             space_size, 12);
  355.   else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
  356.     return constant_space;
  357.   else
  358.     return scale(constant_space*fs.to_scaled_points(),
  359.          units_per_inch, 36*72*sizescale);
  360. }
  361.  
  362. hunits font_info::get_narrow_space_width(font_size fs)
  363. {
  364.   charinfo *ci = get_charinfo(symbol("|"));
  365.   if (fm->contains(ci->get_index()))
  366.     return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
  367.   else
  368.     return hunits(fs.to_units()/6);
  369. }
  370.  
  371. hunits font_info::get_half_narrow_space_width(font_size fs)
  372. {
  373.   charinfo *ci = get_charinfo(symbol("^"));
  374.   if (fm->contains(ci->get_index()))
  375.     return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
  376.   else
  377.     return hunits(fs.to_units()/12);
  378. }
  379.  
  380. /* tfont */
  381.  
  382. tfont_spec::tfont_spec(symbol nm, int n, font *f, 
  383.                font_size s, int h, int sl)
  384.      : name(nm), input_position(n), fm(f), size(s),
  385.      is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
  386.      height(h), slant(sl)
  387. {
  388.   if (height == size.to_scaled_points())
  389.     height = 0;
  390. }
  391.  
  392. int tfont_spec::operator==(const tfont_spec &spec)
  393. {
  394.   if (fm == spec.fm 
  395.       && size == spec.size
  396.       && input_position == spec.input_position
  397.       && name == spec.name
  398.       && height == spec.height
  399.       && slant == spec.slant
  400.       && (is_bold 
  401.       ? (spec.is_bold && bold_offset == spec.bold_offset)
  402.       : !spec.is_bold)
  403.       && track_kern == spec.track_kern
  404.       && (is_constant_spaced
  405.       ? (spec.is_constant_spaced 
  406.          && constant_space_width == spec.constant_space_width)
  407.       : !spec.is_constant_spaced)
  408.       && ligature_mode == spec.ligature_mode
  409.       && kern_mode == spec.kern_mode)
  410.     return 1;
  411.   else
  412.     return 0;
  413. }
  414.  
  415. tfont_spec tfont_spec::plain()
  416. {
  417.   return tfont_spec(name, input_position, fm, size, height, slant);
  418. }
  419.  
  420. hunits tfont::get_width(charinfo *c)
  421. {
  422.   if (is_constant_spaced)
  423.     return constant_space_width;
  424.   else if (is_bold)
  425.     return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
  426.         + track_kern + bold_offset);
  427.   else
  428.     return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) + track_kern);
  429. }
  430.  
  431. vunits tfont::get_char_height(charinfo *c)
  432. {
  433.   vunits v = fm->get_height(c->get_index(), size.to_scaled_points());
  434.   if (height != 0 && height != size.to_scaled_points())
  435.     return scale(v, height, size.to_scaled_points());
  436.   else
  437.     return v;
  438. }
  439.  
  440. vunits tfont::get_char_depth(charinfo *c)
  441. {
  442.   vunits v = fm->get_depth(c->get_index(), size.to_scaled_points());
  443.   if (height != 0 && height != size.to_scaled_points())
  444.     return scale(v, height, size.to_scaled_points());
  445.   else
  446.     return v;
  447. }
  448.  
  449. hunits tfont::get_char_skew(charinfo *c)
  450. {
  451.   return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant));
  452. }
  453.  
  454. hunits tfont::get_italic_correction(charinfo *c)
  455. {
  456.   return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points()));
  457. }
  458.  
  459. hunits tfont::get_left_italic_correction(charinfo *c)
  460. {
  461.   return hunits(fm->get_left_italic_correction(c->get_index(),
  462.                            size.to_scaled_points()));
  463. }
  464.  
  465. hunits tfont::get_subscript_correction(charinfo *c)
  466. {
  467.   return hunits(fm->get_subscript_correction(c->get_index(),
  468.                          size.to_scaled_points()));
  469. }
  470.  
  471. inline int tfont::get_input_position()
  472. {
  473.   return input_position;
  474. }
  475.  
  476. inline int tfont::contains(charinfo *ci)
  477. {
  478.   return fm->contains(ci->get_index());
  479. }
  480.  
  481. inline int tfont::get_character_type(charinfo *ci)
  482. {
  483.   return fm->get_character_type(ci->get_index());
  484. }
  485.  
  486. inline int tfont::get_bold(hunits *res)
  487. {
  488.   if (is_bold) {
  489.     *res = bold_offset;
  490.     return 1;
  491.   }
  492.   else
  493.     return 0;
  494. }
  495.  
  496. inline int tfont::get_constant_space(hunits *res)
  497. {
  498.   if (is_constant_spaced) {
  499.     *res = constant_space_width;
  500.     return 1;
  501.   }
  502.   else
  503.     return 0;
  504. }
  505.  
  506. inline hunits tfont::get_track_kern()
  507. {
  508.   return track_kern;
  509. }
  510.  
  511. inline tfont *tfont::get_plain()
  512. {
  513.   return plain_version;
  514. }
  515.  
  516. inline font_size tfont::get_size()
  517. {
  518.   return size;
  519. }
  520.  
  521. inline symbol tfont::get_name()
  522. {
  523.   return name;
  524. }
  525.  
  526. inline int tfont::get_height()
  527. {
  528.   return height;
  529. }
  530.  
  531. inline int tfont::get_slant()
  532. {
  533.   return slant;
  534. }
  535.  
  536. symbol SYMBOL_ff("ff");
  537. symbol SYMBOL_fi("fi");
  538. symbol SYMBOL_fl("fl");
  539. symbol SYMBOL_Fi("Fi");
  540. symbol SYMBOL_Fl("Fl");
  541.  
  542. charinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
  543. {
  544.   if (ligature_mode == 0)
  545.     return 0;
  546.   charinfo *ci = 0;
  547.   if (c1->get_ascii_code() == 'f') {
  548.     switch (c2->get_ascii_code()) {
  549.     case 'f':
  550.       if (fm->has_ligature(font::LIG_ff))
  551.     ci = get_charinfo(SYMBOL_ff);
  552.       break;
  553.     case 'i':
  554.       if (fm->has_ligature(font::LIG_fi))
  555.     ci = get_charinfo(SYMBOL_fi);
  556.       break;
  557.     case 'l':
  558.       if (fm->has_ligature(font::LIG_fl))
  559.     ci = get_charinfo(SYMBOL_fl);
  560.       break;
  561.     }
  562.   }
  563.   else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
  564.     switch (c2->get_ascii_code()) {
  565.     case 'i':
  566.       if (fm->has_ligature(font::LIG_ffi))
  567.     ci = get_charinfo(SYMBOL_Fi);
  568.       break;
  569.     case 'l':
  570.       if (fm->has_ligature(font::LIG_ffl))
  571.     ci = get_charinfo(SYMBOL_Fl);
  572.       break;
  573.     }
  574.   }
  575.   if (ci != 0 && fm->contains(ci->get_index()))
  576.     return ci;
  577.   return 0;
  578. }
  579.  
  580. inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
  581. {
  582.   if (kern_mode == 0)
  583.     return 0;
  584.   else {
  585.     int n = fm->get_kern(c1->get_index(),
  586.              c2->get_index(),
  587.              size.to_scaled_points());
  588.     if (n) {
  589.       *res = hunits(n);
  590.       return 1;
  591.     }
  592.     else
  593.       return 0;
  594.   }
  595. }
  596.  
  597. tfont *make_tfont(tfont_spec &spec)
  598. {
  599.   for (tfont *p = tfont::tfont_list; p; p = p->next)
  600.     if (*p == spec)
  601.       return p;
  602.   return new tfont(spec);
  603. }
  604.  
  605. tfont *tfont::tfont_list = 0;
  606.  
  607. tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
  608. {
  609.   next = tfont_list;
  610.   tfont_list = this;
  611.   tfont_spec plain_spec = plain();
  612.   tfont *p;
  613.   for (p = tfont_list; p; p = p->next)
  614.     if (*p == plain_spec) {
  615.       plain_version = p;
  616.       break;
  617.     }
  618.   if (!p)
  619.     plain_version = new tfont(plain_spec);
  620. }
  621.  
  622. /* output_file */
  623.  
  624. class real_output_file : public output_file {
  625. #ifndef POPEN_MISSING
  626.   int piped;
  627. #endif
  628.   int printing;
  629.   virtual void really_transparent_char(unsigned char) = 0;
  630.   virtual void really_print_line(hunits x, vunits y, node *n,
  631.                  vunits before, vunits after) = 0;
  632.   virtual void really_begin_page(int pageno, vunits page_length) = 0;
  633.   virtual void really_copy_file(hunits x, vunits y, const char *filename);
  634. protected:
  635.   FILE *fp;
  636. public:
  637.   real_output_file();
  638.   ~real_output_file();
  639.   void flush();
  640.   void transparent_char(unsigned char);
  641.   void print_line(hunits x, vunits y, node *n, vunits before, vunits after);
  642.   void begin_page(int pageno, vunits page_length);
  643.   int is_printing();
  644.   void copy_file(hunits x, vunits y, const char *filename);
  645. };
  646.  
  647. class suppress_output_file : public real_output_file {
  648. public:
  649.   suppress_output_file();
  650.   void really_transparent_char(unsigned char);
  651.   void really_print_line(hunits x, vunits y, node *n, vunits, vunits);
  652.   void really_begin_page(int pageno, vunits page_length);
  653. };
  654.  
  655. class ascii_output_file : public real_output_file {
  656. public:
  657.   ascii_output_file();
  658.   void really_transparent_char(unsigned char);
  659.   void really_print_line(hunits x, vunits y, node *n, vunits, vunits);
  660.   void really_begin_page(int pageno, vunits page_length);
  661.   void outc(unsigned char c);
  662.   void outs(const char *s);
  663. };
  664.  
  665. void ascii_output_file::outc(unsigned char c)
  666. {
  667.   fputc(c, fp);
  668. }
  669.  
  670. void ascii_output_file::outs(const char *s)
  671. {
  672.   fputc('<', fp);
  673.   if (s)
  674.     fputs(s, fp);
  675.   fputc('>', fp);
  676. }
  677.  
  678. struct hvpair;
  679.       
  680. class troff_output_file : public real_output_file {
  681.   units hpos;
  682.   units vpos;
  683.   units output_vpos;
  684.   units output_hpos;
  685.   int force_motion;
  686.   int current_size;
  687.   int current_slant;
  688.   int current_height;
  689.   tfont *current_tfont;
  690.   int current_font_number;
  691.   symbol *font_position;
  692.   int nfont_positions;
  693.   enum { TBUF_SIZE = 256 };
  694.   char tbuf[TBUF_SIZE];
  695.   int tbuf_len;
  696.   int tbuf_kern;
  697.   int begun_page;
  698.   void do_motion();
  699.   void put(char c);
  700.   void put(unsigned char c);
  701.   void put(int i);
  702.   void put(const char *s);
  703.   void set_font(tfont *tf);
  704.   void flush_tbuf();
  705. public:
  706.   troff_output_file();
  707.   ~troff_output_file();
  708.   void trailer(vunits page_length);
  709.   void put_char(charinfo *ci, tfont *tf);
  710.   void put_char_width(charinfo *ci, tfont *tf, hunits w, hunits k);
  711.   void right(hunits);
  712.   void down(vunits);
  713.   void moveto(hunits, vunits);
  714.   void start_special();
  715.   void special_char(unsigned char c);
  716.   void end_special();
  717.   void word_marker();
  718.   void really_transparent_char(unsigned char c);
  719.   void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after);
  720.   void really_begin_page(int pageno, vunits page_length);
  721.   void really_copy_file(hunits x, vunits y, const char *filename);
  722.   void draw(char, hvpair *, int, font_size);
  723.   int get_hpos() { return hpos; }
  724.   int get_vpos() { return vpos; }
  725. };
  726.  
  727. static void put_string(const char *s, FILE *fp)
  728. {
  729.   for (; *s != '\0'; ++s)
  730.     putc(*s, fp);
  731. }
  732.  
  733. inline void troff_output_file::put(char c)
  734. {
  735.   putc(c, fp);
  736. }
  737.  
  738. inline void troff_output_file::put(unsigned char c)
  739. {
  740.   putc(c, fp);
  741. }
  742.  
  743. inline void troff_output_file::put(const char *s)
  744. {
  745.   put_string(s, fp);
  746. }
  747.  
  748. inline void troff_output_file::put(int i)
  749. {
  750.   put_string(itoa(i), fp);
  751. }
  752.  
  753. void troff_output_file::start_special()
  754. {
  755.   flush_tbuf();
  756.   do_motion();
  757.   put("x X ");
  758. }
  759.  
  760. void troff_output_file::special_char(unsigned char c)
  761. {
  762.   put(c);
  763.   if (c == '\n')
  764.     put('+');
  765. }
  766.  
  767. void troff_output_file::end_special()
  768. {
  769.   put('\n');
  770. }
  771.  
  772. inline void troff_output_file::moveto(hunits h, vunits v)
  773. {
  774.   hpos = h.to_units();
  775.   vpos = v.to_units();
  776. }
  777.  
  778. void troff_output_file::really_print_line(hunits x, vunits y, node *n,
  779.                       vunits before, vunits after)
  780. {
  781.   moveto(x, y);
  782.   while (n != 0) {
  783.     n->tprint(this);
  784.     n = n->next;
  785.   }
  786.   flush_tbuf();
  787.   // This ensures that transparent throughput will have a more predictable
  788.   // position.
  789.   do_motion();
  790.   force_motion = 1;
  791.   hpos = 0;
  792.   put('n');
  793.   put(before.to_units());
  794.   put(' ');
  795.   put(after.to_units());
  796.   put('\n');
  797. }
  798.  
  799. inline void troff_output_file::word_marker()
  800. {
  801.   flush_tbuf();
  802.   put('w');
  803. }
  804.  
  805. inline void troff_output_file::right(hunits n)
  806. {
  807.   hpos += n.to_units();
  808. }
  809.  
  810. inline void troff_output_file::down(vunits n)
  811. {
  812.   vpos += n.to_units();
  813. }
  814.  
  815. void troff_output_file::do_motion()
  816. {
  817.   if (force_motion) {
  818.     put('V');
  819.     put(vpos);
  820.     put('\n');
  821.     put('H');
  822.     put(hpos);
  823.     put('\n');
  824.   }
  825.   else {
  826.     if (hpos != output_hpos) {
  827.       units n = hpos - output_hpos;
  828.       if (n > 0 && n < hpos) {
  829.     put('h');
  830.     put(n);
  831.       }
  832.       else {
  833.     put('H');
  834.     put(hpos);
  835.       }
  836.       put('\n');
  837.     }
  838.     if (vpos != output_vpos) {
  839.       units n = vpos - output_vpos;
  840.       if (n > 0 && n < vpos) {
  841.     put('v');
  842.     put(n);
  843.       }
  844.       else {
  845.     put('V');
  846.     put(vpos);
  847.       }
  848.       put('\n');
  849.     }
  850.   }
  851.   output_vpos = vpos;
  852.   output_hpos = hpos;
  853.   force_motion = 0;
  854. }
  855.  
  856. void troff_output_file::flush_tbuf()
  857. {
  858.   if (tbuf_len == 0)
  859.     return;
  860.   if (tbuf_kern == 0)
  861.     put('t');
  862.   else {
  863.     put('u');
  864.     put(tbuf_kern);
  865.     put(' ');
  866.   }
  867.   for (int i = 0; i < tbuf_len; i++)
  868.     put(tbuf[i]);
  869.   put('\n');
  870.   tbuf_len = 0;
  871. }
  872.  
  873. void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
  874.                        hunits k)
  875. {
  876.   if (tf != current_tfont) {
  877.     flush_tbuf();
  878.     set_font(tf);
  879.   }
  880.   char c = ci->get_ascii_code();
  881.   int kk = k.to_units();
  882.   if (c == '\0') {
  883.     flush_tbuf();
  884.     do_motion();
  885.     if (ci->numbered()) {
  886.       put('N');
  887.       put(ci->get_number());
  888.     }
  889.     else {
  890.       put('C');
  891.       const char *s = ci->nm.contents();
  892.       if (s[1] == 0) {
  893.     put('\\');
  894.     put(s[0]);
  895.       }
  896.       else
  897.     put(s);
  898.     }
  899.     put('\n');
  900.     hpos += w.to_units() + kk;
  901.   }
  902.   else if (tcommand_flag) {
  903.     if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
  904.     && kk == tbuf_kern
  905.     && tbuf_len < TBUF_SIZE) {
  906.       tbuf[tbuf_len++] = c;
  907.       output_hpos += w.to_units() + kk;
  908.       hpos = output_hpos;
  909.       return;
  910.     }
  911.     flush_tbuf();
  912.     do_motion();
  913.     tbuf[tbuf_len++] = c;
  914.     output_hpos += w.to_units() + kk;
  915.     tbuf_kern = kk;
  916.     hpos = output_hpos;
  917.   }
  918.   else {
  919.     // flush_tbuf();
  920.     int n = hpos - output_hpos;
  921.     if (vpos == output_vpos && n > 0 && n < 100 && !force_motion) {
  922.       put(char(n/10 + '0'));
  923.       put(char(n%10 + '0'));
  924.       put(c);
  925.       output_hpos = hpos;
  926.     }
  927.     else {
  928.       do_motion();
  929.       put('c');
  930.       put(c);
  931.     }
  932.     hpos += w.to_units() + kk;
  933.   }
  934. }
  935.  
  936. void troff_output_file::put_char(charinfo *ci, tfont *tf)
  937. {
  938.   flush_tbuf();
  939.   if (tf != current_tfont)
  940.     set_font(tf);
  941.   char c = ci->get_ascii_code();
  942.   if (c == '\0') {
  943.     do_motion();
  944.     if (ci->numbered()) {
  945.       put('N');
  946.       put(ci->get_number());
  947.     }
  948.     else {
  949.       put('C');
  950.       const char *s = ci->nm.contents();
  951.       if (s[1] == 0) {
  952.     put('\\');
  953.     put(s[0]);
  954.       }
  955.       else
  956.     put(s);
  957.     }
  958.     put('\n');
  959.   }
  960.   else {
  961.     int n = hpos - output_hpos;
  962.     if (vpos == output_vpos && n > 0 && n < 100) {
  963.       put(char(n/10 + '0'));
  964.       put(char(n%10 + '0'));
  965.       put(c);
  966.       output_hpos = hpos;
  967.     }
  968.     else {
  969.       do_motion();
  970.       put('c');
  971.       put(c);
  972.     }
  973.   }
  974. }
  975.  
  976. void troff_output_file::set_font(tfont *tf)
  977. {
  978.   if (current_tfont == tf)
  979.     return;
  980.   int n = tf->get_input_position();
  981.   symbol nm = tf->get_name();
  982.   if (n >= nfont_positions || font_position[n] != nm) {
  983.     put("x font ");
  984.     put(n);
  985.     put(' ');
  986.     put(nm.contents());
  987.     put('\n');
  988.     if (n >= nfont_positions) {
  989.       int old_nfont_positions = nfont_positions;
  990.       symbol *old_font_position = font_position;
  991.       nfont_positions *= 3;
  992.       nfont_positions /= 2;
  993.       if (nfont_positions <= n)
  994.     nfont_positions = n + 10;
  995.       font_position = new symbol[nfont_positions];
  996.       memcpy(font_position, old_font_position,
  997.          old_nfont_positions*sizeof(symbol));
  998.       a_delete old_font_position;
  999.     }
  1000.     font_position[n] = nm;
  1001.   }
  1002.   if (current_font_number != n) {
  1003.     put('f');
  1004.     put(n);
  1005.     put('\n');
  1006.     current_font_number = n;
  1007.   }
  1008.   int size = tf->get_size().to_scaled_points();
  1009.   if (current_size != size) {
  1010.     put('s');
  1011.     put(size);
  1012.     put('\n');
  1013.     current_size = size;
  1014.   }
  1015.   int slant = tf->get_slant();
  1016.   if (current_slant != slant) {
  1017.     put("x Slant ");
  1018.     put(slant);
  1019.     put('\n');
  1020.     current_slant = slant;
  1021.   }
  1022.   int height = tf->get_height();
  1023.   if (current_height != height) {
  1024.     put("x Height ");
  1025.     put(height == 0 ? current_size : height);
  1026.     put('\n');
  1027.     current_height = height;
  1028.   }
  1029.   current_tfont = tf;
  1030. }
  1031.  
  1032. void troff_output_file::draw(char code, hvpair *point, int npoints,
  1033.                  font_size fsize)
  1034. {
  1035.   flush_tbuf();
  1036.   do_motion();
  1037.   int size = fsize.to_scaled_points();
  1038.   if (current_size != size) {
  1039.     put('s');
  1040.     put(size);
  1041.     put('\n');
  1042.     current_size = size;
  1043.     current_tfont = 0;
  1044.   }
  1045.   put('D');
  1046.   put(code);
  1047.   int i;
  1048.   if (code == 'c') {
  1049.     put(' ');
  1050.     put(point[0].h.to_units());
  1051.   }
  1052.   else
  1053.     for (i = 0; i < npoints; i++) {
  1054.       put(' ');
  1055.       put(point[i].h.to_units());
  1056.       put(' ');
  1057.       put(point[i].v.to_units());
  1058.     }
  1059.   for (i = 0; i < npoints; i++)
  1060.     output_hpos += point[i].h.to_units();
  1061.   hpos = output_hpos;
  1062.   if (code != 'e') {
  1063.     for (i = 0; i < npoints; i++)
  1064.       output_vpos += point[i].v.to_units();
  1065.     vpos = output_vpos;
  1066.   }
  1067.   put('\n');
  1068. }
  1069.  
  1070. void troff_output_file::really_begin_page(int pageno, vunits page_length)
  1071. {
  1072.   flush_tbuf();
  1073.   if (begun_page) {
  1074.     if (page_length > V0) {
  1075.       put('V');
  1076.       put(page_length.to_units());
  1077.       put('\n');
  1078.     }
  1079.   }
  1080.   else
  1081.     begun_page = 1;
  1082.   current_tfont = 0;
  1083.   current_font_number = -1;
  1084.   current_size = 0;
  1085.   // current_height = 0;
  1086.   // current_slant = 0;
  1087.   hpos = 0;
  1088.   vpos = 0;
  1089.   output_hpos = 0;
  1090.   output_vpos = 0;
  1091.   force_motion = 1;
  1092.   for (int i = 0; i < nfont_positions; i++)
  1093.     font_position[i] = NULL_SYMBOL;
  1094.   put('p');
  1095.   put(pageno);
  1096.   put('\n');
  1097. }
  1098.  
  1099. void troff_output_file::really_copy_file(hunits x, vunits y, const char *filename)
  1100. {
  1101.   moveto(x, y);
  1102.   flush_tbuf();
  1103.   do_motion();
  1104.   errno = 0;
  1105.   FILE *ifp = fopen(filename, "r");
  1106.   if (ifp == 0)
  1107.     error("can't open `%1': %2", filename, strerror(errno));
  1108.   else {
  1109.     int c;
  1110.     while ((c = getc(ifp)) != EOF)
  1111.       put(char(c));
  1112.     fclose(ifp);
  1113.   }
  1114.   force_motion = 1;
  1115.   current_size = 0;
  1116.   current_tfont = 0;
  1117.   current_font_number = -1;
  1118.   for (int i = 0; i < nfont_positions; i++)
  1119.     font_position[i] = NULL_SYMBOL;
  1120. }
  1121.   
  1122. void troff_output_file::really_transparent_char(unsigned char c)
  1123. {
  1124.   put(c);
  1125. }
  1126.  
  1127. troff_output_file::~troff_output_file()
  1128. {
  1129.   a_delete font_position;
  1130. }
  1131.  
  1132. void troff_output_file::trailer(vunits page_length)
  1133. {
  1134.   flush_tbuf();
  1135.   if (page_length > V0) {
  1136.     put("x trailer\n");
  1137.     put('V');
  1138.     put(page_length.to_units());
  1139.     put('\n');
  1140.   }
  1141.   put("x stop\n");
  1142. }
  1143.  
  1144. troff_output_file::troff_output_file()
  1145. : current_height(0), current_slant(0), tbuf_len(0), nfont_positions(10),
  1146.   begun_page(0)
  1147. {
  1148.   font_position = new symbol[nfont_positions];
  1149.   put("x T ");
  1150.   put(device);
  1151.   put('\n');
  1152.   put("x res ");
  1153.   put(units_per_inch);
  1154.   put(' ');
  1155.   put(hresolution);
  1156.   put(' ');
  1157.   put(vresolution);
  1158.   put('\n');
  1159.   put("x init\n");
  1160. }
  1161.  
  1162. /* output_file */
  1163.  
  1164. output_file *the_output = 0;
  1165.  
  1166. output_file::output_file()
  1167. {
  1168. }
  1169.  
  1170. output_file::~output_file()
  1171. {
  1172. }
  1173.  
  1174. void output_file::trailer(vunits)
  1175. {
  1176. }
  1177.  
  1178. real_output_file::real_output_file()
  1179. : printing(0)
  1180. {
  1181. #ifndef POPEN_MISSING
  1182.   if (pipe_command) {
  1183.     if ((fp = popen(pipe_command, "w")) != 0) {
  1184.       piped = 1;
  1185.       return;
  1186.     }
  1187.     error("pipe open failed: %1", strerror(errno));
  1188.   }
  1189.   piped = 0;
  1190. #endif /* not POPEN_MISSING */
  1191.   fp = stdout;
  1192. }
  1193.  
  1194. real_output_file::~real_output_file()
  1195. {
  1196.   if (!fp)
  1197.     return;
  1198.   // To avoid looping, set fp to 0 before calling fatal().
  1199.   if (ferror(fp) || fflush(fp) < 0) {
  1200.     fp = 0;
  1201.     fatal("error writing output file");
  1202.   }
  1203. #ifndef POPEN_MISSING
  1204.   if (piped) {
  1205.     int result = pclose(fp);
  1206.     fp = 0;
  1207.     if (result < 0)
  1208.       fatal("pclose failed");
  1209.     if ((result & 0x7f) != 0)
  1210.       error("output process `%1' got fatal signal %2",
  1211.         pipe_command, result & 0x7f);
  1212.     else {
  1213.       int exit_status = (result >> 8) & 0xff;
  1214.       if (exit_status != 0)
  1215.     error("output process `%1' exited with status %2",
  1216.           pipe_command, exit_status);
  1217.     }
  1218.   }
  1219.   else
  1220. #endif /* not POPEN MISSING */
  1221.   if (fclose(fp) < 0) {
  1222.     fp = 0;
  1223.     fatal("error closing output file");
  1224.   }
  1225. }
  1226.  
  1227. void real_output_file::flush()
  1228. {
  1229.   if (fflush(fp) < 0)
  1230.     fatal("error writing output file");
  1231. }
  1232.  
  1233. int real_output_file::is_printing()
  1234. {
  1235.   return printing;
  1236. }
  1237.  
  1238. void real_output_file::begin_page(int pageno, vunits page_length)
  1239. {
  1240.   printing = in_output_page_list(pageno);
  1241.   if (printing)
  1242.     really_begin_page(pageno, page_length);
  1243. }
  1244.  
  1245. void real_output_file::copy_file(hunits x, vunits y, const char *filename)
  1246. {
  1247.   if (printing)
  1248.     really_copy_file(x, y, filename);
  1249. }
  1250.  
  1251. void real_output_file::transparent_char(unsigned char c)
  1252. {
  1253.   if (printing)
  1254.     really_transparent_char(c);
  1255. }
  1256.  
  1257. void real_output_file::print_line(hunits x, vunits y, node *n,
  1258.                  vunits before, vunits after)
  1259. {
  1260.   if (printing)
  1261.     really_print_line(x, y, n, before, after);
  1262.   delete_node_list(n);
  1263. }
  1264.  
  1265. void real_output_file::really_copy_file(hunits, vunits, const char *)
  1266. {
  1267.   // do nothing
  1268. }
  1269.  
  1270.  
  1271. /* ascii_output_file */
  1272.  
  1273. void ascii_output_file::really_transparent_char(unsigned char c)
  1274. {
  1275.   putc(c, fp);
  1276. }
  1277.  
  1278. void ascii_output_file::really_print_line(hunits, vunits, node *n, vunits, vunits)
  1279. {
  1280.   while (n != 0) {
  1281.     n->ascii_print(this);
  1282.     n = n->next;
  1283.   }
  1284.   fputc('\n', fp);
  1285. }
  1286.  
  1287. void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
  1288. {
  1289.   fputs("<beginning of page>\n", fp);
  1290. }
  1291.  
  1292. ascii_output_file::ascii_output_file()
  1293. {
  1294. }
  1295.  
  1296. /* suppress_output_file */
  1297.  
  1298. suppress_output_file::suppress_output_file()
  1299. {
  1300. }
  1301.  
  1302. void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits)
  1303. {
  1304. }
  1305.  
  1306. void suppress_output_file::really_begin_page(int, vunits)
  1307. {
  1308. }
  1309.  
  1310. void suppress_output_file::really_transparent_char(unsigned char)
  1311. {
  1312. }
  1313.  
  1314. /* glyphs, ligatures, kerns, discretionary breaks */
  1315.  
  1316. class charinfo_node : public node {
  1317. protected:
  1318.   charinfo *ci;
  1319. public:
  1320.   charinfo_node(charinfo *, node * = 0);
  1321.   int ends_sentence();
  1322.   int overlaps_vertically();
  1323.   int overlaps_horizontally();
  1324. };
  1325.  
  1326. charinfo_node::charinfo_node(charinfo *c, node *x)
  1327. : ci(c), node(x)
  1328. {
  1329. }
  1330.  
  1331. int charinfo_node::ends_sentence()
  1332. {
  1333.   if (ci->ends_sentence())
  1334.     return 1;
  1335.   else if (ci->transparent())
  1336.     return 2;
  1337.   else
  1338.     return 0;
  1339. }
  1340.  
  1341. int charinfo_node::overlaps_horizontally()
  1342. {
  1343.   return ci->overlaps_horizontally();
  1344. }
  1345.  
  1346. int charinfo_node::overlaps_vertically()
  1347. {
  1348.   return ci->overlaps_vertically();
  1349. }
  1350.  
  1351. class glyph_node : public charinfo_node {
  1352.   static glyph_node *free_list;
  1353. protected:
  1354.   tfont *tf;
  1355. #ifdef STORE_WIDTH
  1356.   hunits wid;
  1357.   glyph_node(charinfo *, tfont *, hunits, node * = 0);
  1358. #endif
  1359. public:
  1360.   void *operator new(size_t);
  1361.   void operator delete(void *);
  1362.   glyph_node(charinfo *, tfont *, node * = 0);
  1363.   ~glyph_node() {}
  1364.   node *copy();
  1365.   node *merge_glyph_node(glyph_node *);
  1366.   node *merge_self(node *);
  1367.   hunits width();
  1368.   node *last_char_node();
  1369.   units size();
  1370.   void vertical_extent(vunits *, vunits *);
  1371.   hunits subscript_correction();
  1372.   hunits italic_correction();
  1373.   hunits left_italic_correction();
  1374.   hunits skew();
  1375.   hyphenation_type get_hyphenation_type();
  1376.   tfont *get_tfont();
  1377.   void tprint(troff_output_file *);
  1378.   void zero_width_tprint(troff_output_file *);
  1379.   hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
  1380.   node *add_self(node *, hyphen_list **);
  1381.   void ascii_print(ascii_output_file *);
  1382.   void asciify(macro *);
  1383.   int character_type();
  1384.   int same(node *);
  1385.   const char *type();
  1386. };
  1387.  
  1388. glyph_node *glyph_node::free_list = 0;
  1389.  
  1390. class ligature_node : public glyph_node {
  1391.   node *n1;
  1392.   node *n2;
  1393. #ifdef STORE_WIDTH
  1394.   ligature_node(charinfo *, tfont *, hunits, node *gn1, node *gn2, node *x = 0);
  1395. #endif
  1396. public:
  1397.   void *operator new(size_t);
  1398.   void operator delete(void *);
  1399.   ligature_node(charinfo *, tfont *, node *gn1, node *gn2, node *x = 0);
  1400.   ~ligature_node();
  1401.   node *copy();
  1402.   node *add_self(node *, hyphen_list **);
  1403.   hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
  1404.   void ascii_print(ascii_output_file *);
  1405.   void asciify(macro *);
  1406.   int same(node *);
  1407.   const char *type();
  1408. };
  1409.  
  1410. class kern_pair_node : public node {
  1411.   hunits amount;
  1412.   node *n1;
  1413.   node *n2;
  1414. public:
  1415.   kern_pair_node(hunits n, node *first, node *second, node *x = 0);
  1416.   ~kern_pair_node();
  1417.   node *copy();
  1418.   node *merge_glyph_node(glyph_node *);
  1419.   node *add_self(node *, hyphen_list **);
  1420.   hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
  1421.   node *add_discretionary_hyphen();
  1422.   hunits width();
  1423.   node *last_char_node();
  1424.   hunits italic_correction();
  1425.   hunits subscript_correction();
  1426.   void tprint(troff_output_file *);
  1427.   hyphenation_type get_hyphenation_type();
  1428.   int ends_sentence();
  1429.   void ascii_print(ascii_output_file *);
  1430.   void asciify(macro *);
  1431.   int same(node *);
  1432.   const char *type();
  1433.   void vertical_extent(vunits *, vunits *);
  1434. };
  1435.  
  1436. class dbreak_node : public node {
  1437.   node *none;
  1438.   node *pre;
  1439.   node *post;
  1440. public:
  1441.   dbreak_node(node *n, node *p, node *x = 0);
  1442.   ~dbreak_node();
  1443.   node *copy();
  1444.   node *merge_glyph_node(glyph_node *);
  1445.   node *add_discretionary_hyphen();
  1446.   hunits width();
  1447.   node *last_char_node();
  1448.   hunits italic_correction();
  1449.   hunits subscript_correction();
  1450.   void tprint(troff_output_file *);
  1451.   breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
  1452.                   int is_inner = 0);
  1453.   int nbreaks();
  1454.   int ends_sentence();
  1455.   void split(int, node **, node **);
  1456.   hyphenation_type get_hyphenation_type();
  1457.   void ascii_print(ascii_output_file *);
  1458.   void asciify(macro *);
  1459.   int same(node *);
  1460.   const char *type();
  1461. };
  1462.  
  1463. void *glyph_node::operator new(size_t n)
  1464. {
  1465.   assert(n == sizeof(glyph_node));
  1466.   if (!free_list) {
  1467.     const int BLOCK = 1024;
  1468.     free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
  1469.     for (int i = 0; i < BLOCK - 1; i++)
  1470.       free_list[i].next = free_list + i + 1;
  1471.     free_list[BLOCK-1].next = 0;
  1472.   }
  1473.   glyph_node *p = free_list;
  1474.   free_list = (glyph_node *)(free_list->next);
  1475.   p->next = 0;
  1476.   return p;
  1477. }
  1478.  
  1479. void *ligature_node::operator new(size_t n)
  1480. {
  1481.   return new char[n];
  1482. }
  1483.  
  1484. void glyph_node::operator delete(void *p)
  1485. {
  1486.   if (p) {
  1487.     ((glyph_node *)p)->next = free_list;
  1488.     free_list = (glyph_node *)p;
  1489.   }
  1490. }
  1491.  
  1492. void ligature_node::operator delete(void *p)
  1493. {
  1494.   delete p;
  1495. }
  1496.  
  1497. glyph_node::glyph_node(charinfo *c, tfont *t, node *x)
  1498. : charinfo_node(c, x), tf(t)
  1499. {
  1500. #ifdef STORE_WIDTH
  1501.   wid = tf->get_width(ci);
  1502. #endif
  1503. }
  1504.  
  1505. #ifdef STORE_WIDTH
  1506. glyph_node::glyph_node(charinfo *c, tfont *t, hunits w, node *x)
  1507. : charinfo_node(c, x), tf(t), wid(w)
  1508. {
  1509. }
  1510. #endif
  1511.  
  1512. node *glyph_node::copy()
  1513. {
  1514. #ifdef STORE_WIDTH
  1515.   return new glyph_node(ci, tf, wid);
  1516. #else
  1517.   return new glyph_node(ci, tf);
  1518. #endif
  1519. }
  1520.  
  1521. node *glyph_node::merge_self(node *nd)
  1522. {
  1523.   return nd->merge_glyph_node(this);
  1524. }
  1525.  
  1526. int glyph_node::character_type()
  1527. {
  1528.   return tf->get_character_type(ci);
  1529. }
  1530.  
  1531. node *glyph_node::add_self(node *n, hyphen_list **p)
  1532. {
  1533.   assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
  1534.   next = 0;
  1535.   node *nn;
  1536.   if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
  1537.     next = n;
  1538.     nn = this;
  1539.   }
  1540.   if ((*p)->hyphen)
  1541.     nn = nn->add_discretionary_hyphen();
  1542.   hyphen_list *pp = *p;
  1543.   *p = (*p)->next;
  1544.   delete pp;
  1545.   return nn;
  1546. }
  1547.  
  1548. units glyph_node::size()
  1549. {
  1550.   return tf->get_size().to_units();
  1551. }
  1552.  
  1553. hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail)
  1554. {
  1555.   return new hyphen_list(ci->get_hyphenation_code(), tail);
  1556. }
  1557.  
  1558.  
  1559. tfont *node::get_tfont()
  1560. {
  1561.   return 0;
  1562. }
  1563.  
  1564. tfont *glyph_node::get_tfont()
  1565. {
  1566.   return tf;
  1567. }
  1568.  
  1569. node *node::merge_glyph_node(glyph_node * /*gn*/)
  1570. {
  1571.   return 0;
  1572. }
  1573.  
  1574. node *glyph_node::merge_glyph_node(glyph_node *gn)
  1575. {
  1576.   if (tf == gn->tf) {
  1577.     charinfo *lig;
  1578.     if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
  1579.       node *next1 = next;
  1580.       next = 0;
  1581.       return new ligature_node(lig, tf, this, gn, next1);
  1582.     }
  1583.     hunits kern;
  1584.     if (tf->get_kern(ci, gn->ci, &kern)) {
  1585.       node *next1 = next;
  1586.       next = 0;
  1587.       return new kern_pair_node(kern, this, gn, next1);
  1588.     }
  1589.   }
  1590.   return 0;
  1591. }
  1592.  
  1593. #ifdef STORE_WIDTH
  1594. inline
  1595. #endif
  1596. hunits glyph_node::width()
  1597. {
  1598. #ifdef STORE_WIDTH
  1599.   return wid;
  1600. #else
  1601.   return tf->get_width(ci);
  1602. #endif
  1603. }
  1604.  
  1605. node *glyph_node::last_char_node()
  1606. {
  1607.   return this;
  1608. }
  1609.  
  1610. void glyph_node::vertical_extent(vunits *min, vunits *max)
  1611. {
  1612.   *min = -tf->get_char_height(ci);
  1613.   *max = tf->get_char_depth(ci);
  1614. }
  1615.  
  1616. hunits glyph_node::skew()
  1617. {
  1618.   return tf->get_char_skew(ci);
  1619. }
  1620.  
  1621. hunits glyph_node::subscript_correction()
  1622. {
  1623.   return tf->get_subscript_correction(ci);
  1624. }
  1625.  
  1626. hunits glyph_node::italic_correction()
  1627. {
  1628.   return tf->get_italic_correction(ci);
  1629. }
  1630.  
  1631. hunits glyph_node::left_italic_correction()
  1632. {
  1633.   return tf->get_left_italic_correction(ci);
  1634. }
  1635.  
  1636. hyphenation_type glyph_node::get_hyphenation_type()
  1637. {
  1638.   return HYPHEN_MIDDLE;
  1639. }
  1640.  
  1641. void glyph_node::ascii_print(ascii_output_file *ascii)
  1642. {
  1643.   unsigned char c = ci->get_ascii_code();
  1644.   if (c != 0)
  1645.     ascii->outc(c);
  1646.   else
  1647.     ascii->outs(ci->nm.contents());
  1648. }
  1649.  
  1650. ligature_node::ligature_node(charinfo *c, tfont *t, 
  1651.                  node *gn1, node *gn2, node *x)
  1652.      : glyph_node(c, t, x), n1(gn1), n2(gn2)
  1653. {
  1654. }
  1655.  
  1656. #ifdef STORE_WIDTH
  1657. ligature_node::ligature_node(charinfo *c, tfont *t, hunits w,
  1658.                    node *gn1, node *gn2, node *x)
  1659.      : glyph_node(c, t, w, x), n1(gn1), n2(gn2)
  1660. {
  1661. }
  1662. #endif
  1663.  
  1664. ligature_node::~ligature_node()
  1665. {
  1666.   delete n1;
  1667.   delete n2;
  1668. }
  1669.  
  1670. node *ligature_node::copy()
  1671. {
  1672. #ifdef STORE_WIDTH
  1673.   return new ligature_node(ci, tf, wid, n1->copy(), n2->copy());
  1674. #else
  1675.   return new ligature_node(ci, tf, n1->copy(), n2->copy());
  1676. #endif
  1677. }
  1678.  
  1679. void ligature_node::ascii_print(ascii_output_file *ascii)
  1680. {
  1681.   n1->ascii_print(ascii);
  1682.   n2->ascii_print(ascii);
  1683. }
  1684.  
  1685. hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail)
  1686. {
  1687.   return n1->get_hyphen_list(n2->get_hyphen_list(tail));
  1688. }
  1689.  
  1690. node *ligature_node::add_self(node *n, hyphen_list **p)
  1691. {
  1692.   n = n1->add_self(n, p);
  1693.   n = n2->add_self(n, p);
  1694.   n1 = n2 = 0;
  1695.   delete this;
  1696.   return n;
  1697. }
  1698.  
  1699. kern_pair_node::kern_pair_node(hunits n, node *first, node *second, node *x)
  1700.      : node(x), n1(first), n2(second), amount(n)
  1701. {
  1702. }
  1703.  
  1704. dbreak_node::dbreak_node(node *n, node *p, node *x) 
  1705.      : node(x), none(n), pre(p), post(0)
  1706. {
  1707. }
  1708.  
  1709. node *dbreak_node::merge_glyph_node(glyph_node *gn)
  1710. {
  1711.   glyph_node *gn2 = (glyph_node *)gn->copy();
  1712.   node *new_none = none ? none->merge_glyph_node(gn) : 0;
  1713.   node *new_post = post ? post->merge_glyph_node(gn2) : 0;
  1714.   if (new_none == 0 && new_post == 0) {
  1715.     delete gn2;
  1716.     return 0;
  1717.   }
  1718.   if (new_none != 0)
  1719.     none = new_none;
  1720.   else {
  1721.     gn->next = none;
  1722.     none = gn;
  1723.   }
  1724.   if (new_post != 0)
  1725.     post = new_post;
  1726.   else {
  1727.     gn2->next = post;
  1728.     post = gn2;
  1729.   }
  1730.   return this;
  1731. }
  1732.  
  1733. node *kern_pair_node::merge_glyph_node(glyph_node *gn)
  1734. {
  1735.   node *nd = n2->merge_glyph_node(gn);
  1736.   if (nd == 0)
  1737.     return 0;
  1738.   n2 = nd;
  1739.   nd = n2->merge_self(n1);
  1740.   if (nd) {
  1741.     nd->next = next;
  1742.     n1 = 0;
  1743.     n2 = 0;
  1744.     delete this;
  1745.     return nd;
  1746.   }
  1747.   return this;
  1748. }
  1749.  
  1750.  
  1751. hunits kern_pair_node::italic_correction()
  1752. {
  1753.   return n2->italic_correction();
  1754. }
  1755.  
  1756. hunits kern_pair_node::subscript_correction()
  1757. {
  1758.   return n2->subscript_correction();
  1759. }
  1760.  
  1761. void kern_pair_node::vertical_extent(vunits *min, vunits *max)
  1762. {
  1763.   n1->vertical_extent(min, max);
  1764.   vunits min2, max2;
  1765.   n2->vertical_extent(&min2, &max2);
  1766.   if (min2 < *min)
  1767.     *min = min2;
  1768.   if (max2 > *max)
  1769.     *max = max2;
  1770. }
  1771.   
  1772. node *kern_pair_node::add_discretionary_hyphen()
  1773. {
  1774.   tfont *tf = n2->get_tfont();
  1775.   if (tf) {
  1776.     if (tf->contains(soft_hyphen_char)) {
  1777.       node *next1 = next;
  1778.       next = 0;
  1779.       node *n = copy();
  1780.       glyph_node *gn = new glyph_node(soft_hyphen_char, tf);
  1781.       node *nn = n->merge_glyph_node(gn);
  1782.       if (nn == 0) {
  1783.     gn->next = n;
  1784.     nn = gn;
  1785.       }
  1786.       return new dbreak_node(this, nn, next1);
  1787.     }
  1788.   }
  1789.   return this;
  1790. }
  1791.  
  1792.  
  1793. kern_pair_node::~kern_pair_node()
  1794. {
  1795.   if (n1 != 0)
  1796.     delete n1;
  1797.   if (n2 != 0)
  1798.     delete n2;
  1799. }
  1800.  
  1801. dbreak_node::~dbreak_node()
  1802. {
  1803.   delete_node_list(pre);
  1804.   delete_node_list(post);
  1805.   delete_node_list(none);
  1806. }
  1807.  
  1808. node *kern_pair_node::copy()
  1809. {
  1810.   return new kern_pair_node(amount, n1->copy(), n2->copy());
  1811. }
  1812.  
  1813. node *copy_node_list(node *n)
  1814. {
  1815.   node *p = 0;
  1816.   while (n != 0) {
  1817.     node *nn = n->copy();
  1818.     nn->next = p;
  1819.     p = nn;
  1820.     n = n->next;
  1821.   }
  1822.   while (p != 0) {
  1823.     node *pp = p->next;
  1824.     p->next = n;
  1825.     n = p;
  1826.     p = pp;
  1827.   }
  1828.   return n;
  1829. }
  1830.  
  1831. void delete_node_list(node *n)
  1832. {
  1833.   while (n != 0) {
  1834.     node *tem = n;
  1835.     n = n->next;
  1836.     delete tem;
  1837.   }
  1838. }
  1839.  
  1840. node *dbreak_node::copy()
  1841. {
  1842.   dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre));
  1843.   p->post = copy_node_list(post);
  1844.   return p;
  1845. }
  1846.  
  1847. hyphen_list *node::get_hyphen_list(hyphen_list *tail)
  1848. {
  1849.   return tail;
  1850. }
  1851.  
  1852.  
  1853. hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail)
  1854. {
  1855.   return n1->get_hyphen_list(n2->get_hyphen_list(tail));
  1856. }
  1857.  
  1858. class hyphen_inhibitor_node : public node {
  1859. public:
  1860.   hyphen_inhibitor_node(node *nd = 0);
  1861.   node *copy();
  1862.   int same(node *);
  1863.   const char *type();
  1864.   hyphenation_type get_hyphenation_type();
  1865. };
  1866.  
  1867. hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd)
  1868. {
  1869. }
  1870.  
  1871. node *hyphen_inhibitor_node::copy()
  1872. {
  1873.   return new hyphen_inhibitor_node;
  1874. }
  1875.  
  1876. int hyphen_inhibitor_node::same(node *)
  1877. {
  1878.   return 1;
  1879. }
  1880.  
  1881. const char *hyphen_inhibitor_node::type()
  1882. {
  1883.   return "hyphen_inhibitor_node";
  1884. }
  1885.  
  1886. hyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
  1887. {
  1888.   return HYPHEN_INHIBIT;
  1889. }
  1890.  
  1891. /* add_discretionary_hyphen methods */
  1892.  
  1893. node *dbreak_node::add_discretionary_hyphen()
  1894. {
  1895.   if (post)
  1896.     post = post->add_discretionary_hyphen();
  1897.   if (none)
  1898.     none = none->add_discretionary_hyphen();
  1899.   return this;
  1900. }
  1901.  
  1902.  
  1903. node *node::add_discretionary_hyphen()
  1904. {
  1905.   tfont *tf = get_tfont();
  1906.   if (!tf)
  1907.     return new hyphen_inhibitor_node(this);
  1908.   if (tf->contains(soft_hyphen_char)) {
  1909.     node *next1 = next;
  1910.     next = 0;
  1911.     node *n = copy();
  1912.     glyph_node *gn = new glyph_node(soft_hyphen_char, tf);
  1913.     node *n1 = n->merge_glyph_node(gn);
  1914.     if (n1 == 0) {
  1915.       gn->next = n;
  1916.       n1 = gn;
  1917.     }
  1918.     return new dbreak_node(this, n1, next1);
  1919.   }
  1920.   return this;
  1921. }
  1922.  
  1923.  
  1924. node *node::merge_self(node *)
  1925. {
  1926.   return 0;
  1927. }
  1928.  
  1929. node *node::add_self(node *n, hyphen_list ** /*p*/)
  1930. {
  1931.   next = n;
  1932.   return this;
  1933. }
  1934.  
  1935. node *kern_pair_node::add_self(node *n, hyphen_list **p)
  1936. {
  1937.   n = n1->add_self(n, p);
  1938.   n = n2->add_self(n, p);
  1939.   n1 = n2 = 0;
  1940.   delete this;
  1941.   return n;
  1942. }
  1943.  
  1944.  
  1945. hunits node::width()
  1946. {
  1947.   return H0;
  1948. }
  1949.  
  1950. node *node::last_char_node()
  1951. {
  1952.   return 0;
  1953. }
  1954.  
  1955. hunits hmotion_node::width()
  1956. {
  1957.   return n;
  1958. }
  1959.  
  1960. units node::size()
  1961. {
  1962.   return points_to_units(10);
  1963. }
  1964.  
  1965. hunits kern_pair_node::width()
  1966. {
  1967.   return n1->width() + n2->width() + amount;
  1968. }
  1969.  
  1970. node *kern_pair_node::last_char_node()
  1971. {
  1972.   node *nd = n2->last_char_node();
  1973.   if (nd)
  1974.     return nd;
  1975.   return n1->last_char_node();
  1976. }
  1977.  
  1978. hunits dbreak_node::width()
  1979. {
  1980.   hunits x = H0;
  1981.   for (node *n = none; n != 0; n = n->next)
  1982.     x += n->width();
  1983.   return x;
  1984. }
  1985.  
  1986. node *dbreak_node::last_char_node()
  1987. {
  1988.   for (node *n = none; n; n = n->next) {
  1989.     node *last = n->last_char_node();
  1990.     if (last)
  1991.       return last;
  1992.   }
  1993.   return 0;
  1994. }
  1995.  
  1996. hunits dbreak_node::italic_correction()
  1997. {
  1998.   return none ? none->italic_correction() : H0;
  1999. }
  2000.  
  2001. hunits dbreak_node::subscript_correction()
  2002. {
  2003.   return none ? none->subscript_correction() : H0;
  2004. }
  2005.  
  2006. class italic_corrected_node : public node {
  2007.   node *n;
  2008.   hunits x;
  2009. public:
  2010.   italic_corrected_node(node *, hunits, node * = 0);
  2011.   ~italic_corrected_node();
  2012.   node *copy();
  2013.   void ascii_print(ascii_output_file *);
  2014.   void asciify(macro *m);
  2015.   hunits width();
  2016.   node *last_char_node();
  2017.   void vertical_extent(vunits *, vunits *);
  2018.   int ends_sentence();
  2019.   int overlaps_horizontally();
  2020.   int overlaps_vertically();
  2021.   int same(node *);
  2022.   hyphenation_type get_hyphenation_type();
  2023.   tfont *get_tfont();
  2024.   hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
  2025.   int character_type();
  2026.   void tprint(troff_output_file *);
  2027.   hunits subscript_correction();
  2028.   hunits skew();
  2029.   node *add_self(node *, hyphen_list **);
  2030.   const char *type();
  2031. };
  2032.  
  2033. node *node::add_italic_correction(hunits *width)
  2034. {
  2035.   hunits ic = italic_correction();
  2036.   if (ic.is_zero())
  2037.     return this;
  2038.   else {
  2039.     node *next1 = next;
  2040.     next = 0;
  2041.     *width += ic;
  2042.     return new italic_corrected_node(this, ic, next1);
  2043.   }
  2044. }
  2045.  
  2046. italic_corrected_node::italic_corrected_node(node *nn, hunits xx, node *p)
  2047. : n(nn), x(xx), node(p)
  2048. {
  2049.   assert(n != 0);
  2050. }
  2051.  
  2052. italic_corrected_node::~italic_corrected_node()
  2053. {
  2054.   delete n;
  2055. }
  2056.  
  2057. node *italic_corrected_node::copy()
  2058. {
  2059.   return new italic_corrected_node(n->copy(), x);
  2060. }
  2061.  
  2062. hunits italic_corrected_node::width()
  2063. {
  2064.   return n->width() + x;
  2065. }
  2066.  
  2067. void italic_corrected_node::vertical_extent(vunits *min, vunits *max)
  2068. {
  2069.   n->vertical_extent(min, max);
  2070. }
  2071.  
  2072. void italic_corrected_node::tprint(troff_output_file *out)
  2073. {
  2074.   n->tprint(out);
  2075.   out->right(x);
  2076. }
  2077.  
  2078. hunits italic_corrected_node::skew()
  2079. {
  2080.   return n->skew() - x/2;
  2081. }
  2082.  
  2083. hunits italic_corrected_node::subscript_correction()
  2084. {
  2085.   return n->subscript_correction() - x;
  2086. }
  2087.  
  2088. void italic_corrected_node::ascii_print(ascii_output_file *out)
  2089. {
  2090.   n->ascii_print(out);
  2091. }
  2092.  
  2093. int italic_corrected_node::ends_sentence()
  2094. {
  2095.   return n->ends_sentence();
  2096. }
  2097.  
  2098. int italic_corrected_node::overlaps_horizontally()
  2099. {
  2100.   return n->overlaps_horizontally();
  2101. }
  2102.  
  2103. int italic_corrected_node::overlaps_vertically()
  2104. {
  2105.   return n->overlaps_vertically();
  2106. }
  2107.  
  2108. node *italic_corrected_node::last_char_node()
  2109. {
  2110.   return n->last_char_node();
  2111. }
  2112.  
  2113. tfont *italic_corrected_node::get_tfont()
  2114. {
  2115.   return n->get_tfont();
  2116. }
  2117.  
  2118. hyphenation_type italic_corrected_node::get_hyphenation_type()
  2119. {
  2120.   return n->get_hyphenation_type();
  2121. }
  2122.  
  2123. node *italic_corrected_node::add_self(node *nd, hyphen_list **p)
  2124. {
  2125.   nd = n->add_self(nd, p);
  2126.   hunits not_interested;
  2127.   nd = nd->add_italic_correction(¬_interested);
  2128.   n = 0;
  2129.   delete this;
  2130.   return nd;
  2131. }
  2132.  
  2133. hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail)
  2134. {
  2135.   return n->get_hyphen_list(tail);
  2136. }
  2137.  
  2138. int italic_corrected_node::character_type()
  2139. {
  2140.   return n->character_type();
  2141. }
  2142.  
  2143. class break_char_node : public node {
  2144.   node *ch;
  2145.   char break_code;
  2146. public:
  2147.   break_char_node(node *, int, node * = 0);
  2148.   ~break_char_node();
  2149.   node *copy();
  2150.   hunits width();
  2151.   vunits vertical_width();
  2152.   node *last_char_node();
  2153.   int character_type();
  2154.   int ends_sentence();
  2155.   node *add_self(node *, hyphen_list **);
  2156.   hyphen_list *get_hyphen_list(hyphen_list *s = 0);
  2157.   void tprint(troff_output_file *);
  2158.   void zero_width_tprint(troff_output_file *);
  2159.   void ascii_print(ascii_output_file *);
  2160.   void asciify(macro *m);
  2161.   hyphenation_type get_hyphenation_type();
  2162.   int overlaps_vertically();
  2163.   int overlaps_horizontally();
  2164.   units size();
  2165.   tfont *get_tfont();
  2166.   int same(node *);
  2167.   const char *type();
  2168. };
  2169.  
  2170. break_char_node::break_char_node(node *n, int c, node *x)
  2171. : node(x), ch(n), break_code(c)
  2172. {
  2173. }
  2174.  
  2175. break_char_node::~break_char_node()
  2176. {
  2177.   delete ch;
  2178. }
  2179.  
  2180. node *break_char_node::copy()
  2181. {
  2182.   return new break_char_node(ch->copy(), break_code);
  2183. }
  2184.  
  2185. hunits break_char_node::width()
  2186. {
  2187.   return ch->width();
  2188. }
  2189.  
  2190. vunits break_char_node::vertical_width()
  2191. {
  2192.   return ch->vertical_width();
  2193. }
  2194.  
  2195. node *break_char_node::last_char_node()
  2196. {
  2197.   return ch->last_char_node();
  2198. }
  2199.  
  2200. int break_char_node::character_type()
  2201. {
  2202.   return ch->character_type();
  2203. }
  2204.  
  2205. int break_char_node::ends_sentence()
  2206. {
  2207.   return ch->ends_sentence();
  2208. }
  2209.  
  2210. node *break_char_node::add_self(node *n, hyphen_list **p)
  2211. {
  2212.   assert((*p)->hyphenation_code == 0);
  2213.   if ((*p)->breakable && (break_code & 1)) {
  2214.     n = new space_node(H0, n);
  2215.     n->freeze_space();
  2216.   }
  2217.   next = n;
  2218.   n = this;
  2219.   if ((*p)->breakable && (break_code & 2)) {
  2220.     n = new space_node(H0, n);
  2221.     n->freeze_space();
  2222.   }
  2223.   hyphen_list *pp = *p;
  2224.   *p = (*p)->next;
  2225.   delete pp;
  2226.   return n;
  2227. }
  2228.  
  2229. hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail)
  2230. {
  2231.   return new hyphen_list(0, tail);
  2232. }
  2233.  
  2234. hyphenation_type break_char_node::get_hyphenation_type()
  2235. {
  2236.   return HYPHEN_MIDDLE;
  2237. }
  2238.  
  2239. void break_char_node::ascii_print(ascii_output_file *ascii)
  2240. {
  2241.   ch->ascii_print(ascii);
  2242. }
  2243.  
  2244. int break_char_node::overlaps_vertically()
  2245. {
  2246.   return ch->overlaps_vertically();
  2247. }
  2248.  
  2249. int break_char_node::overlaps_horizontally()
  2250. {
  2251.   return ch->overlaps_horizontally();
  2252. }
  2253.  
  2254. units break_char_node::size()
  2255. {
  2256.   return ch->size();
  2257. }
  2258.  
  2259. tfont *break_char_node::get_tfont()
  2260. {
  2261.   return ch->get_tfont();
  2262. }
  2263.  
  2264. node *extra_size_node::copy()
  2265.   return new extra_size_node(n); 
  2266. }
  2267.  
  2268. node *vertical_size_node::copy()
  2269.   return new vertical_size_node(n); 
  2270. }
  2271.  
  2272. node *hmotion_node::copy()
  2273.   return new hmotion_node(n);
  2274. }
  2275.  
  2276. node *space_char_hmotion_node::copy()
  2277. {
  2278.   return new space_char_hmotion_node(n);
  2279. }
  2280.  
  2281. node *vmotion_node::copy()
  2282.   return new vmotion_node(n);
  2283. }
  2284.   
  2285. node *dummy_node::copy()
  2286.   return new dummy_node;
  2287. }
  2288.  
  2289. node *transparent_dummy_node::copy()
  2290.   return new transparent_dummy_node;
  2291. }
  2292.  
  2293. hline_node::~hline_node()
  2294. {
  2295.   if (n)
  2296.     delete n;
  2297. }
  2298.  
  2299. node *hline_node::copy()
  2300. {
  2301.   return new hline_node(x, n ? n->copy() : 0);
  2302. }
  2303.  
  2304. hunits hline_node::width()
  2305. {
  2306.   return x < H0 ? H0 : x;
  2307. }
  2308.  
  2309.  
  2310. vline_node::~vline_node()
  2311. {
  2312.   if (n)
  2313.     delete n;
  2314. }
  2315.  
  2316. node *vline_node::copy()
  2317. {
  2318.   return new vline_node(x, n ? n->copy() : 0);
  2319. }
  2320.  
  2321. hunits vline_node::width()
  2322. {
  2323.   return n == 0 ? H0 : n->width();
  2324. }
  2325.  
  2326.  
  2327. zero_width_node::zero_width_node(node *nd) : n(nd)
  2328. {
  2329. }
  2330.  
  2331. zero_width_node::~zero_width_node()
  2332. {
  2333.   delete_node_list(n);
  2334. }
  2335.  
  2336. node *zero_width_node::copy()
  2337. {
  2338.   return new zero_width_node(copy_node_list(n));
  2339. }
  2340.  
  2341. int node_list_character_type(node *p)
  2342. {
  2343.   int t = 0;
  2344.   for (; p; p = p->next)
  2345.     t |= p->character_type();
  2346.   return t;
  2347. }
  2348.  
  2349. int zero_width_node::character_type()
  2350. {
  2351.   return node_list_character_type(n);
  2352. }
  2353.  
  2354. void node_list_vertical_extent(node *p, vunits *min, vunits *max)
  2355. {
  2356.   *min = V0;
  2357.   *max = V0;
  2358.   vunits cur_vpos = V0;
  2359.   vunits v1, v2;
  2360.   for (; p; p = p->next) {
  2361.     p->vertical_extent(&v1, &v2);
  2362.     v1 += cur_vpos;
  2363.     if (v1 < *min)
  2364.       *min = v1;
  2365.     v2 += cur_vpos;
  2366.     if (v2 > *max)
  2367.       *max = v2;
  2368.     cur_vpos += p->vertical_width();
  2369.   }
  2370. }
  2371.  
  2372. void zero_width_node::vertical_extent(vunits *min, vunits *max)
  2373. {
  2374.   node_list_vertical_extent(n, min, max);
  2375. }
  2376.  
  2377. overstrike_node::overstrike_node() : max_width(H0), list(0)
  2378. {
  2379. }
  2380.  
  2381. overstrike_node::~overstrike_node()
  2382. {
  2383.   delete_node_list(list);
  2384. }
  2385.  
  2386. node *overstrike_node::copy()
  2387. {
  2388.   overstrike_node *on = new overstrike_node;
  2389.   for (node *tem = list; tem; tem = tem->next)
  2390.     on->overstrike(tem->copy());
  2391.   return on;
  2392. }
  2393.  
  2394. void overstrike_node::overstrike(node *n)
  2395. {
  2396.   if (n == 0)
  2397.     return;
  2398.   hunits w = n->width();
  2399.   if (w > max_width)
  2400.     max_width = w;
  2401.   node **p;
  2402.   for (p = &list; *p; p = &(*p)->next)
  2403.     ;
  2404.   n->next = 0;
  2405.   *p = n;
  2406. }
  2407.  
  2408. hunits overstrike_node::width()
  2409. {
  2410.   return max_width;
  2411. }
  2412.  
  2413. bracket_node::bracket_node() : max_width(H0), list(0)
  2414. {
  2415. }
  2416.  
  2417. bracket_node::~bracket_node()
  2418. {
  2419.   delete_node_list(list);
  2420. }
  2421.  
  2422. node *bracket_node::copy()
  2423. {
  2424.   bracket_node *on = new bracket_node;
  2425.   for (node *tem = list; tem; tem = tem->next)
  2426.     on->bracket(tem->copy());
  2427.   return on;
  2428. }
  2429.  
  2430.  
  2431. void bracket_node::bracket(node *n)
  2432. {
  2433.   if (n == 0)
  2434.     return;
  2435.   hunits w = n->width();
  2436.   if (w > max_width)
  2437.     max_width = w;
  2438.   n->next = list;
  2439.   list = n;
  2440. }
  2441.  
  2442. hunits bracket_node::width()
  2443. {
  2444.   return max_width;
  2445. }
  2446.  
  2447. int node::nspaces()
  2448. {
  2449.   return 0;
  2450. }
  2451.  
  2452. int node::merge_space(hunits)
  2453. {
  2454.   return 0;
  2455. }
  2456.  
  2457. #if 0
  2458. space_node *space_node::free_list = 0;
  2459.  
  2460. void *space_node::operator new(size_t n)
  2461. {
  2462.   assert(n == sizeof(space_node));
  2463.   if (!free_list) {
  2464.     free_list = (space_node *)new char[sizeof(space_node)*BLOCK];
  2465.     for (int i = 0; i < BLOCK - 1; i++)
  2466.       free_list[i].next = free_list + i + 1;
  2467.     free_list[BLOCK-1].next = 0;
  2468.   }
  2469.   space_node *p = free_list;
  2470.   free_list = (space_node *)(free_list->next);
  2471.   p->next = 0;
  2472.   return p;
  2473. }
  2474.  
  2475. inline void space_node::operator delete(void *p)
  2476. {
  2477.   if (p) {
  2478.     ((space_node *)p)->next = free_list;
  2479.     free_list = (space_node *)p;
  2480.   }
  2481. }
  2482. #endif
  2483.  
  2484. space_node::space_node(hunits nn, node *p) : node(p), n(nn), set(0)
  2485. {
  2486. }
  2487.  
  2488. space_node::space_node(hunits nn, int s, node *p) : node(p), n(nn), set(s)
  2489. {
  2490. }
  2491.  
  2492. #if 0
  2493. space_node::~space_node()
  2494. {
  2495. }
  2496. #endif
  2497.  
  2498. node *space_node::copy()
  2499. {
  2500.   return new space_node(n, set);
  2501. }
  2502.  
  2503. int space_node::nspaces()
  2504. {
  2505.   return set ? 0 : 1;
  2506. }
  2507.  
  2508. int space_node::merge_space(hunits h)
  2509. {
  2510.   n += h;
  2511.   return 1;
  2512. }
  2513.  
  2514. hunits space_node::width()
  2515. {
  2516.   return n;
  2517. }
  2518.  
  2519. void node::spread_space(int*, hunits*)
  2520. {
  2521. }
  2522.  
  2523. void space_node::spread_space(int *nspaces, hunits *desired_space)
  2524. {
  2525.   if (!set) {
  2526.     assert(*nspaces > 0);
  2527.     if (*nspaces == 1) {
  2528.       n += *desired_space;
  2529.       *desired_space = H0;
  2530.     }
  2531.     else {
  2532.       hunits extra = *desired_space / *nspaces;
  2533.       *desired_space -= extra;
  2534.       n += extra;
  2535.     }
  2536.     *nspaces -= 1;
  2537.     set = 1;
  2538.   }
  2539. }
  2540.  
  2541. void node::freeze_space()
  2542. {
  2543. }
  2544.  
  2545. void space_node::freeze_space()
  2546. {
  2547.   set = 1;
  2548. }
  2549.  
  2550. diverted_space_node::diverted_space_node(vunits d, node *p)
  2551. : node(p), n(d)
  2552. {
  2553. }
  2554.  
  2555. node *diverted_space_node::copy()
  2556. {
  2557.   return new diverted_space_node(n);
  2558. }
  2559.  
  2560. diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p)
  2561. : node(p), filename(s)
  2562. {
  2563. }
  2564.  
  2565. node *diverted_copy_file_node::copy()
  2566. {
  2567.   return new diverted_copy_file_node(filename);
  2568. }
  2569.  
  2570. int node::ends_sentence()
  2571. {
  2572.   return 0;
  2573. }
  2574.  
  2575. int kern_pair_node::ends_sentence()
  2576. {
  2577.   switch (n2->ends_sentence()) {
  2578.   case 0:
  2579.     return 0;
  2580.   case 1:
  2581.     return 1;
  2582.   case 2:
  2583.     break;
  2584.   default:
  2585.     assert(0);
  2586.   }
  2587.   return n1->ends_sentence();
  2588. }
  2589.  
  2590. int node_list_ends_sentence(node *n)
  2591. {
  2592.   for (; n != 0; n = n->next)
  2593.     switch (n->ends_sentence()) {
  2594.     case 0:
  2595.       return 0;
  2596.     case 1:
  2597.       return 1;
  2598.     case 2:
  2599.       break;
  2600.     default:
  2601.       assert(0);
  2602.     }
  2603.   return 2;
  2604. }
  2605.  
  2606.     
  2607. int dbreak_node::ends_sentence()
  2608. {
  2609.   return node_list_ends_sentence(none);
  2610. }
  2611.  
  2612.  
  2613. int node::overlaps_horizontally()
  2614. {
  2615.   return 0;
  2616. }
  2617.  
  2618. int node::overlaps_vertically()
  2619. {
  2620.   return 0;
  2621. }
  2622.  
  2623. int node::discardable()
  2624. {
  2625.   return 0;
  2626. }
  2627.  
  2628. int space_node::discardable()
  2629. {
  2630.   return set ? 0 : 1;
  2631. }
  2632.  
  2633.  
  2634. vunits node::vertical_width()
  2635. {
  2636.   return V0;
  2637. }
  2638.  
  2639. vunits vline_node::vertical_width()
  2640. {
  2641.   return x;
  2642. }
  2643.  
  2644. vunits vmotion_node::vertical_width()
  2645. {
  2646.   return n;
  2647. }
  2648.  
  2649. int node::character_type()
  2650. {
  2651.   return 0;
  2652. }
  2653.  
  2654. hunits node::subscript_correction()
  2655. {
  2656.   return H0;
  2657. }
  2658.  
  2659. hunits node::italic_correction()
  2660. {
  2661.   return H0;
  2662. }
  2663.  
  2664. hunits node::left_italic_correction()
  2665. {
  2666.   return H0;
  2667. }
  2668.  
  2669. hunits node::skew()
  2670. {
  2671.   return H0;
  2672. }
  2673.  
  2674.  
  2675. /* vertical_extent methods */
  2676.  
  2677. void node::vertical_extent(vunits *min, vunits *max)
  2678. {
  2679.   vunits v = vertical_width();
  2680.   if (v < V0) {
  2681.     *min = v;
  2682.     *max = V0;
  2683.   }
  2684.   else {
  2685.     *max = v;
  2686.     *min = V0;
  2687.   }
  2688. }
  2689.  
  2690. void vline_node::vertical_extent(vunits *min, vunits *max)
  2691. {
  2692.   if (n == 0)
  2693.     node::vertical_extent(min, max);
  2694.   else {
  2695.     vunits cmin, cmax;
  2696.     n->vertical_extent(&cmin, &cmax);
  2697.     vunits h = n->size();
  2698.     if (x < V0) {
  2699.       if (-x < h) {
  2700.     *min = x;
  2701.     *max = V0;
  2702.       }
  2703.       else {
  2704.     // we print the first character and then move up, so
  2705.     *max = cmax;
  2706.     // we print the last character and then move up h
  2707.     *min = cmin + h;
  2708.     if (*min > V0)
  2709.       *min = V0;
  2710.     *min += x;
  2711.       }
  2712.     }
  2713.     else {
  2714.       if (x < h) {
  2715.     *max = x;
  2716.     *min = V0;
  2717.       }
  2718.       else {
  2719.     // we move down by h and then print the first character, so
  2720.     *min = cmin + h;
  2721.     if (*min > V0)
  2722.       *min = V0;
  2723.     *max = x + cmax;
  2724.       }
  2725.     }
  2726.   }
  2727. }
  2728.  
  2729. /* ascii_print methods */
  2730.  
  2731.  
  2732. static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n)
  2733. {
  2734.   if (n == 0)
  2735.     return;
  2736.   ascii_print_reverse_node_list(ascii, n->next);
  2737.   n->ascii_print(ascii);
  2738. }
  2739.  
  2740. void dbreak_node::ascii_print(ascii_output_file *ascii)
  2741. {
  2742.   ascii_print_reverse_node_list(ascii, none);
  2743. }
  2744.  
  2745. void kern_pair_node::ascii_print(ascii_output_file *ascii)
  2746. {
  2747.   n1->ascii_print(ascii);
  2748.   n2->ascii_print(ascii);
  2749. }
  2750.  
  2751.  
  2752. void node::ascii_print(ascii_output_file *)
  2753. {
  2754. }
  2755.  
  2756. void space_node::ascii_print(ascii_output_file *ascii)
  2757. {
  2758.   if (!n.is_zero())
  2759.     ascii->outc(' ');
  2760. }
  2761.  
  2762. void hmotion_node::ascii_print(ascii_output_file *ascii)
  2763. {
  2764.   // this is pretty arbitrary
  2765.   if (n >= points_to_units(2))
  2766.     ascii->outc(' ');
  2767. }
  2768.  
  2769. void space_char_hmotion_node::ascii_print(ascii_output_file *ascii)
  2770. {
  2771.   ascii->outc(' ');
  2772. }
  2773.  
  2774. /* asciify methods */
  2775.  
  2776. void node::asciify(macro *m)
  2777. {
  2778.   m->append(this);
  2779. }
  2780.       
  2781. void glyph_node::asciify(macro *m)
  2782. {
  2783.   unsigned char c = ci->get_ascii_code();
  2784.   if (c != 0) {
  2785.     m->append(c);
  2786.     delete this;
  2787.   }
  2788.   else
  2789.     m->append(this);
  2790. }
  2791.  
  2792. void kern_pair_node::asciify(macro *m)
  2793. {
  2794.   n1->asciify(m);
  2795.   n2->asciify(m);
  2796.   n1 = n2 = 0;
  2797.   delete this;
  2798. }
  2799.  
  2800. static void asciify_reverse_node_list(macro *m, node *n)
  2801. {
  2802.   if (n == 0)
  2803.     return;
  2804.   asciify_reverse_node_list(m, n->next);
  2805.   n->asciify(m);
  2806. }
  2807.  
  2808. void dbreak_node::asciify(macro *m)
  2809. {
  2810.   asciify_reverse_node_list(m, none);
  2811.   none = 0;
  2812.   delete this;
  2813. }
  2814.  
  2815. void ligature_node::asciify(macro *m)
  2816. {
  2817.   n1->asciify(m);
  2818.   n2->asciify(m);
  2819.   n1 = n2 = 0;
  2820.   delete this;
  2821. }
  2822.  
  2823. void break_char_node::asciify(macro *m)
  2824. {
  2825.   ch->asciify(m);
  2826.   ch = 0;
  2827.   delete this;
  2828. }
  2829.  
  2830. void italic_corrected_node::asciify(macro *m)
  2831. {
  2832.   n->asciify(m);
  2833.   n = 0;
  2834.   delete this;
  2835. }
  2836.  
  2837. void left_italic_corrected_node::asciify(macro *m)
  2838. {
  2839.   if (n) {
  2840.     n->asciify(m);
  2841.     n = 0;
  2842.   }
  2843.   delete this;
  2844. }
  2845.  
  2846. space_char_hmotion_node::space_char_hmotion_node(hunits i, node *next)
  2847. : hmotion_node(i, next)
  2848. {
  2849. }
  2850.  
  2851. void space_char_hmotion_node::asciify(macro *m)
  2852. {
  2853.   m->append(' ');
  2854.   delete this;
  2855. }
  2856.  
  2857. void line_start_node::asciify(macro *)
  2858. {
  2859.   delete this;
  2860. }
  2861.  
  2862. void vertical_size_node::asciify(macro *)
  2863. {
  2864.   delete this;
  2865. }
  2866.  
  2867. breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/,
  2868.                   breakpoint *rest, int /*is_inner*/)
  2869. {
  2870.   return rest;
  2871. }
  2872.  
  2873. int node::nbreaks()
  2874. {
  2875.   return 0;
  2876. }
  2877.  
  2878. breakpoint *space_node::get_breakpoints(hunits width, int ns, breakpoint *rest,
  2879.                 int is_inner)
  2880. {
  2881.   if (next->discardable())
  2882.     return rest;
  2883.   breakpoint *bp = new breakpoint;
  2884.   bp->next = rest;
  2885.   bp->width = width;
  2886.   bp->nspaces = ns;
  2887.   bp->hyphenated = 0;
  2888.   if (is_inner) {
  2889.     assert(rest != 0);
  2890.     bp->index = rest->index + 1;
  2891.     bp->nd = rest->nd;
  2892.   }
  2893.   else {
  2894.     bp->nd = this;
  2895.     bp->index = 0;
  2896.   }
  2897.   return bp;
  2898. }
  2899.  
  2900. int space_node::nbreaks()
  2901. {
  2902.   if (next->discardable())
  2903.     return 0;
  2904.   else
  2905.     return 1;
  2906. }
  2907.  
  2908. static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp,
  2909.                          int ns, breakpoint *rest)
  2910. {
  2911.   if (p != 0) {
  2912.     rest = p->get_breakpoints(*widthp, 
  2913.                   ns, 
  2914.                   node_list_get_breakpoints(p->next, widthp, ns,
  2915.                             rest),
  2916.                   1);
  2917.     *widthp += p->width();
  2918.   }
  2919.   return rest;
  2920. }
  2921.  
  2922.  
  2923. breakpoint *dbreak_node::get_breakpoints(hunits width, int ns,
  2924.                      breakpoint *rest, int is_inner)
  2925. {
  2926.   breakpoint *bp = new breakpoint;
  2927.   bp->next = rest;
  2928.   bp->width = width;
  2929.   for (node *tem = pre; tem != 0; tem = tem->next)
  2930.     bp->width += tem->width();
  2931.   bp->nspaces = ns;
  2932.   bp->hyphenated = 1;
  2933.   if (is_inner) {
  2934.     assert(rest != 0);
  2935.     bp->index = rest->index + 1;
  2936.     bp->nd = rest->nd;
  2937.   }
  2938.   else {
  2939.     bp->nd = this;
  2940.     bp->index = 0;
  2941.   }
  2942.   return node_list_get_breakpoints(none, &width, ns, bp);
  2943. }
  2944.  
  2945. int dbreak_node::nbreaks()
  2946. {
  2947.   int i = 1;
  2948.   for (node *tem = none; tem != 0; tem = tem->next)
  2949.     i += tem->nbreaks();
  2950.   return i;
  2951. }
  2952.  
  2953. void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/)
  2954. {
  2955.   assert(0);
  2956. }
  2957.  
  2958. void space_node::split(int where, node **pre, node **post)
  2959. {
  2960.   assert(where == 0);
  2961.   *pre = next;
  2962.   *post = 0;
  2963.   delete this;
  2964. }
  2965.  
  2966. static void node_list_split(node *p, int *wherep, node **prep, node **postp)
  2967. {
  2968.   if (p == 0)
  2969.     return;
  2970.   int nb = p->nbreaks();
  2971.   node_list_split(p->next, wherep, prep, postp);
  2972.   if (*wherep < 0) {
  2973.     p->next = *postp;
  2974.     *postp = p;
  2975.   }
  2976.   else if (*wherep < nb) {
  2977.     p->next = *prep;
  2978.     p->split(*wherep, prep, postp);
  2979.   }
  2980.   else {
  2981.     p->next = *prep;
  2982.     *prep = p;
  2983.   }
  2984.   *wherep -= nb;
  2985. }
  2986.  
  2987. void dbreak_node::split(int where, node **prep, node **postp)
  2988. {
  2989.   assert(where >= 0);
  2990.   if (where == 0) {
  2991.     *postp = post;
  2992.     post = 0;
  2993.     if (pre == 0)
  2994.       *prep = next;
  2995.     else {
  2996.       node *tem;
  2997.       for (tem = pre; tem->next != 0; tem = tem->next)
  2998.     ;
  2999.       tem->next = next;
  3000.       *prep = pre;
  3001.     }
  3002.     pre = 0;
  3003.     delete this;
  3004.   }
  3005.   else {
  3006.     *prep = next;
  3007.     where -= 1;
  3008.     node_list_split(none, &where, prep, postp);
  3009.     none = 0;
  3010.     delete this;
  3011.   }
  3012. }
  3013.   
  3014.  
  3015. hyphenation_type node::get_hyphenation_type()
  3016. {
  3017.   return HYPHEN_BOUNDARY;
  3018. }
  3019.  
  3020.  
  3021. hyphenation_type dbreak_node::get_hyphenation_type()
  3022. {
  3023.   return HYPHEN_INHIBIT;
  3024. }
  3025.  
  3026. hyphenation_type kern_pair_node::get_hyphenation_type()
  3027. {
  3028.   return HYPHEN_MIDDLE;
  3029. }
  3030.  
  3031. hyphenation_type dummy_node::get_hyphenation_type()
  3032. {
  3033.   return HYPHEN_MIDDLE;
  3034. }
  3035.  
  3036. hyphenation_type transparent_dummy_node::get_hyphenation_type()
  3037. {
  3038.   return HYPHEN_MIDDLE;
  3039. }
  3040.  
  3041. int node::interpret(macro *)
  3042. {
  3043.   return 0;
  3044. }
  3045.  
  3046. special_node::special_node(const macro &m)
  3047. : mac(m)
  3048. {
  3049. }
  3050.  
  3051. int special_node::same(node *n)
  3052. {
  3053.   return mac == ((special_node *)n)->mac;
  3054. }
  3055.  
  3056. const char *special_node::type()
  3057. {
  3058.   return "special_node";
  3059. }
  3060.  
  3061. node *special_node::copy()
  3062. {
  3063.   return new special_node(mac);
  3064. }
  3065.  
  3066. void special_node::tprint_start(troff_output_file *out)
  3067. {
  3068.   out->start_special();
  3069. }
  3070.  
  3071. void special_node::tprint_char(troff_output_file *out, unsigned char c)
  3072. {
  3073.   out->special_char(c);
  3074. }
  3075.  
  3076. void special_node::tprint_end(troff_output_file *out)
  3077. {
  3078.   out->end_special();
  3079. }
  3080.  
  3081. /* composite_node */
  3082.  
  3083. class composite_node : public charinfo_node {
  3084.   node *n;
  3085.   tfont *tf;
  3086. public:
  3087.   composite_node(node *, charinfo *, tfont *, node * = 0);
  3088.   ~composite_node();
  3089.   node *copy();
  3090.   hunits width();
  3091.   node *last_char_node();
  3092.   units size();
  3093.   void tprint(troff_output_file *);
  3094.   hyphenation_type get_hyphenation_type();
  3095.   void ascii_print(ascii_output_file *);
  3096.   void asciify(macro *);
  3097.   hyphen_list *get_hyphen_list(hyphen_list *tail);
  3098.   node *add_self(node *, hyphen_list **);
  3099.   tfont *get_tfont();
  3100.   int same(node *);
  3101.   const char *type();
  3102.   void vertical_extent(vunits *, vunits *);
  3103.   vunits vertical_width();
  3104. };
  3105.  
  3106. composite_node::composite_node(node *p, charinfo *c, tfont *t, node *x)
  3107. : charinfo_node(c, x), n(p), tf(t)
  3108. {
  3109. }
  3110.  
  3111. composite_node::~composite_node()
  3112. {
  3113.   delete_node_list(n);
  3114. }
  3115.  
  3116. node *composite_node::copy()
  3117. {
  3118.   return new composite_node(copy_node_list(n), ci, tf);
  3119. }
  3120.  
  3121. hunits composite_node::width()
  3122. {
  3123.   hunits x;
  3124.   if (tf->get_constant_space(&x))
  3125.     return x;
  3126.   x = H0;
  3127.   for (node *tem = n; tem; tem = tem->next)
  3128.     x += tem->width();
  3129.   hunits offset;
  3130.   if (tf->get_bold(&offset))
  3131.     x += offset;
  3132.   x += tf->get_track_kern();
  3133.   return x;
  3134. }
  3135.  
  3136. node *composite_node::last_char_node()
  3137. {
  3138.   return this;
  3139. }
  3140.  
  3141. vunits composite_node::vertical_width()
  3142. {
  3143.   vunits v = V0;
  3144.   for (node *tem = n; tem; tem = tem->next)
  3145.     v += tem->vertical_width();
  3146.   return v;
  3147. }
  3148.  
  3149. units composite_node::size()
  3150. {
  3151.   return tf->get_size().to_units();
  3152. }
  3153.  
  3154. hyphenation_type composite_node::get_hyphenation_type()
  3155. {
  3156.   return HYPHEN_MIDDLE;
  3157. }
  3158.  
  3159. void composite_node::asciify(macro *m)
  3160. {
  3161.   unsigned char c = ci->get_ascii_code();
  3162.   if (c != 0) {
  3163.     m->append(c);
  3164.     delete this;
  3165.   }
  3166.   else
  3167.     m->append(this);
  3168. }
  3169.  
  3170. void composite_node::ascii_print(ascii_output_file *ascii)
  3171. {
  3172.   unsigned char c = ci->get_ascii_code();
  3173.   if (c != 0)
  3174.     ascii->outc(c);
  3175.   else
  3176.     ascii->outs(ci->nm.contents());
  3177.  
  3178. }
  3179.  
  3180. hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail)
  3181. {
  3182.   return new hyphen_list(ci->get_hyphenation_code(), tail);
  3183.  
  3184. }
  3185.  
  3186. node *composite_node::add_self(node *nn, hyphen_list **p)
  3187. {
  3188.   assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
  3189.   next = nn;
  3190.   nn = this;
  3191.   if ((*p)->hyphen)
  3192.     nn = nn->add_discretionary_hyphen();
  3193.   hyphen_list *pp = *p;
  3194.   *p = (*p)->next;
  3195.   delete pp;
  3196.   return nn;
  3197. }
  3198.  
  3199. tfont *composite_node::get_tfont()
  3200. {
  3201.   return tf;
  3202. }
  3203.  
  3204. node *reverse_node_list(node *n)
  3205. {
  3206.   node *r = 0;
  3207.   while (n) {
  3208.     node *tem = n;
  3209.     n = n->next;
  3210.     tem->next = r;
  3211.     r = tem;
  3212.   }
  3213.   return r;
  3214. }
  3215.  
  3216. void composite_node::vertical_extent(vunits *min, vunits *max)
  3217. {
  3218.   n = reverse_node_list(n);
  3219.   node_list_vertical_extent(n, min, max);
  3220.   n = reverse_node_list(n);
  3221. }
  3222.  
  3223. word_space_node::word_space_node(hunits d, node *x) : space_node(d, x)
  3224. {
  3225. }
  3226.  
  3227. word_space_node::word_space_node(hunits d, int s, node *x)
  3228. : space_node(d, s, x)
  3229. {
  3230. }
  3231.  
  3232. node *word_space_node::copy()
  3233. {
  3234.   return new word_space_node(n, set);
  3235. }
  3236.  
  3237. void word_space_node::tprint(troff_output_file *out)
  3238. {
  3239.   out->word_marker();
  3240.   space_node::tprint(out);
  3241. }
  3242.  
  3243. unbreakable_space_node::unbreakable_space_node(hunits d, node *x)
  3244. : word_space_node(d, x)
  3245. {
  3246. }
  3247.  
  3248. unbreakable_space_node::unbreakable_space_node(hunits d, int s, node *x)
  3249. : word_space_node(d, s, x)
  3250. {
  3251. }
  3252.  
  3253. node *unbreakable_space_node::copy()
  3254. {
  3255.   return new unbreakable_space_node(n, set);
  3256. }
  3257.  
  3258. breakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
  3259.                             breakpoint *rest, int)
  3260. {
  3261.   return rest;
  3262. }
  3263.  
  3264. int unbreakable_space_node::nbreaks()
  3265. {
  3266.   return 0;
  3267. }
  3268.  
  3269. void unbreakable_space_node::split(int, node **, node **)
  3270. {
  3271.   assert(0);
  3272. }
  3273.  
  3274. int unbreakable_space_node::merge_space(hunits)
  3275. {
  3276.   return 0;
  3277. }
  3278.  
  3279. hvpair::hvpair()
  3280. {
  3281. }
  3282.  
  3283. draw_node::draw_node(char c, hvpair *p, int np, font_size s)
  3284.      : code(c), npoints(np), sz(s)
  3285. {
  3286.   point = new hvpair[npoints];
  3287.   for (int i = 0; i < npoints; i++)
  3288.     point[i] = p[i];
  3289. }
  3290.  
  3291. int draw_node::same(node *n)
  3292. {
  3293.   draw_node *nd = (draw_node *)n;
  3294.   if (code != nd->code || npoints != nd->npoints || sz != nd->sz)
  3295.     return 0;
  3296.   for (int i = 0; i < npoints; i++)
  3297.     if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
  3298.       return 0;
  3299.   return 1;
  3300. }
  3301.  
  3302. const char *draw_node::type()
  3303. {
  3304.   return "draw_node";
  3305. }
  3306.  
  3307. draw_node::~draw_node()
  3308. {
  3309.   if (point)
  3310.     a_delete point;
  3311. }
  3312.  
  3313. hunits draw_node::width()
  3314. {
  3315.   hunits x = H0;
  3316.   for (int i = 0; i < npoints; i++)
  3317.     x += point[i].h;
  3318.   return x;
  3319. }
  3320.  
  3321. vunits draw_node::vertical_width()
  3322. {
  3323.   if (code == 'e')
  3324.     return V0;
  3325.   vunits x = V0;
  3326.   for (int i = 0; i < npoints; i++)
  3327.     x += point[i].v;
  3328.   return x;
  3329. }
  3330.  
  3331. node *draw_node::copy()
  3332. {
  3333.   return new draw_node(code, point, npoints, sz);
  3334. }
  3335.  
  3336. void draw_node::tprint(troff_output_file *out)
  3337. {
  3338.   out->draw(code, point, npoints, sz);
  3339. }
  3340.   
  3341. /* tprint methods */
  3342.  
  3343. void glyph_node::tprint(troff_output_file *out)
  3344. {
  3345.   tfont *ptf = tf->get_plain();
  3346.   if (ptf == tf)
  3347.     out->put_char_width(ci, ptf, width(), H0);
  3348.   else {
  3349.     hunits offset;
  3350.     int bold = tf->get_bold(&offset);
  3351.     hunits w = ptf->get_width(ci);
  3352.     hunits k = H0;
  3353.     hunits x;
  3354.     int cs = tf->get_constant_space(&x);
  3355.     if (cs) {
  3356.       x -= w;
  3357.       if (bold)
  3358.     x -= offset;
  3359.       hunits x2 = x/2;
  3360.       out->right(x2);
  3361.       k = x - x2;
  3362.     }
  3363.     else
  3364.       k = tf->get_track_kern();
  3365.     if (bold) {
  3366.       out->put_char(ci, ptf);
  3367.       out->right(offset);
  3368.     }
  3369.     out->put_char_width(ci, ptf, w, k);
  3370.   }
  3371. }
  3372.  
  3373. void glyph_node::zero_width_tprint(troff_output_file *out)
  3374. {
  3375.   tfont *ptf = tf->get_plain();
  3376.   hunits offset;
  3377.   int bold = tf->get_bold(&offset);
  3378.   hunits x;
  3379.   int cs = tf->get_constant_space(&x);
  3380.   if (cs) {
  3381.     x -= ptf->get_width(ci);
  3382.     if (bold)
  3383.       x -= offset;
  3384.     x = x/2;
  3385.     out->right(x);
  3386.   }
  3387.   out->put_char(ci, ptf);
  3388.   if (bold) {
  3389.     out->right(offset);
  3390.     out->put_char(ci, ptf);
  3391.     out->right(-offset);
  3392.   }
  3393.   if (cs)
  3394.     out->right(-x);
  3395. }
  3396.  
  3397. void break_char_node::tprint(troff_output_file *t)
  3398. {
  3399.   ch->tprint(t);
  3400. }
  3401.  
  3402. void break_char_node::zero_width_tprint(troff_output_file *t)
  3403. {
  3404.   ch->zero_width_tprint(t);
  3405. }
  3406.  
  3407. void hline_node::tprint(troff_output_file *out)
  3408. {
  3409.   if (x < H0) {
  3410.     out->right(x);
  3411.     x = -x;
  3412.   }
  3413.   if (n == 0) {
  3414.     out->right(x);
  3415.     return;
  3416.   }
  3417.   hunits w = n->width();
  3418.   if (w <= H0) {
  3419.     error("horizontal line drawing character must have positive width");
  3420.     out->right(x);
  3421.     return;
  3422.   }
  3423.   int i = int(x/w);
  3424.   if (i == 0) {
  3425.     hunits xx = x - w;
  3426.     hunits xx2 = xx/2;
  3427.     out->right(xx2);
  3428.     n->tprint(out);
  3429.     out->right(xx - xx2);
  3430.   }
  3431.   else {
  3432.     hunits rem = x - w*i;
  3433.     if (rem > H0)
  3434.       if (n->overlaps_horizontally()) {
  3435.     n->tprint(out);
  3436.     out->right(rem - w);
  3437.       }
  3438.       else
  3439.     out->right(rem);
  3440.     while (--i >= 0)
  3441.       n->tprint(out);
  3442.   }
  3443. }
  3444.  
  3445. void vline_node::tprint(troff_output_file *out)
  3446. {
  3447.   if (n == 0) {
  3448.     out->down(x);
  3449.     return;
  3450.   }
  3451.   vunits h = n->size();
  3452.   int overlaps = n->overlaps_vertically();
  3453.   vunits y = x;
  3454.   if (y < V0) {
  3455.     y = -y;
  3456.     int i = y / h;
  3457.     vunits rem = y - i*h;
  3458.     if (i == 0) {
  3459.       out->right(n->width());
  3460.       out->down(-rem);
  3461.     }
  3462.     else {
  3463.       while (--i > 0) {
  3464.     n->zero_width_tprint(out);
  3465.     out->down(-h);
  3466.       }
  3467.       if (overlaps) {
  3468.     n->zero_width_tprint(out);
  3469.     out->down(-rem);
  3470.     n->tprint(out);
  3471.     out->down(-h);
  3472.       }
  3473.       else {
  3474.     n->tprint(out);
  3475.     out->down(-h - rem);
  3476.       }
  3477.     }
  3478.   }
  3479.   else {
  3480.     int i = y / h;
  3481.     vunits rem = y - i*h;
  3482.     if (i == 0) {
  3483.       out->down(rem);
  3484.       out->right(n->width());
  3485.     }
  3486.     else {
  3487.       out->down(h);
  3488.       if (overlaps)
  3489.     n->zero_width_tprint(out);
  3490.       out->down(rem);
  3491.       while (--i > 0) {
  3492.     n->zero_width_tprint(out);
  3493.     out->down(h);
  3494.       }
  3495.       n->tprint(out);
  3496.     }
  3497.   }
  3498. }
  3499.  
  3500. void zero_width_node::tprint(troff_output_file *out)
  3501. {
  3502.   if (!n)
  3503.     return;
  3504.   if (!n->next) {
  3505.     n->zero_width_tprint(out);
  3506.     return;
  3507.   }
  3508.   int hpos = out->get_hpos();
  3509.   int vpos = out->get_vpos();
  3510.   node *tem = n;
  3511.   while (tem) {
  3512.     tem->tprint(out);
  3513.     tem = tem->next;
  3514.   }
  3515.   out->moveto(hpos, vpos);
  3516. }
  3517.  
  3518. void overstrike_node::tprint(troff_output_file *out)
  3519. {
  3520.   hunits pos = H0;
  3521.   for (node *tem = list; tem; tem = tem->next) {
  3522.     hunits x = (max_width - tem->width())/2;
  3523.     out->right(x - pos);
  3524.     pos = x;
  3525.     tem->zero_width_tprint(out);
  3526.   }
  3527.   out->right(max_width - pos);
  3528. }
  3529.  
  3530. void bracket_node::tprint(troff_output_file *out)
  3531. {
  3532.   if (list == 0)
  3533.     return;
  3534.   int npieces = 0;
  3535.   node *tem;
  3536.   for (tem = list; tem; tem = tem->next)
  3537.     ++npieces;
  3538.   vunits h = list->size();
  3539.   vunits totalh = h*npieces;
  3540.   vunits y = (totalh - h)/2;
  3541.   out->down(y);
  3542.   for (tem = list; tem; tem = tem->next) {
  3543.     tem->zero_width_tprint(out);
  3544.     out->down(-h);
  3545.   }
  3546.   out->right(max_width);
  3547.   out->down(totalh - y);
  3548. }
  3549.  
  3550. void node::tprint(troff_output_file *)
  3551. {
  3552. }
  3553.  
  3554. void node::zero_width_tprint(troff_output_file *out)
  3555. {
  3556.   int hpos = out->get_hpos();
  3557.   int vpos = out->get_vpos();
  3558.   tprint(out);
  3559.   out->moveto(hpos, vpos);
  3560. }
  3561.  
  3562. void space_node::tprint(troff_output_file *out)
  3563. {
  3564.   out->right(n);
  3565. }
  3566.  
  3567. void hmotion_node::tprint(troff_output_file *out)
  3568. {
  3569.   out->right(n);
  3570. }
  3571.  
  3572. void vmotion_node::tprint(troff_output_file *out)
  3573. {
  3574.   out->down(n);
  3575. }
  3576.  
  3577. void kern_pair_node::tprint(troff_output_file *out)
  3578. {
  3579.   n1->tprint(out);
  3580.   out->right(amount);
  3581.   n2->tprint(out);
  3582. }
  3583.  
  3584. static void tprint_reverse_node_list(troff_output_file *out, node *n)
  3585. {
  3586.   if (n == 0)
  3587.     return;
  3588.   tprint_reverse_node_list(out, n->next);
  3589.   n->tprint(out);
  3590. }
  3591.  
  3592. void dbreak_node::tprint(troff_output_file *out)
  3593. {
  3594.   tprint_reverse_node_list(out, none);
  3595. }
  3596.  
  3597. void composite_node::tprint(troff_output_file *out)
  3598. {
  3599.   hunits bold_offset;
  3600.   int is_bold = tf->get_bold(&bold_offset);
  3601.   hunits track_kern = tf->get_track_kern();
  3602.   hunits constant_space;
  3603.   int is_constant_spaced = tf->get_constant_space(&constant_space);
  3604.   hunits x = H0;
  3605.   if (is_constant_spaced) {
  3606.     x = constant_space;
  3607.     for (node *tem = n; tem; tem = tem->next)
  3608.       x -= tem->width();
  3609.     if (is_bold)
  3610.       x -= bold_offset;
  3611.     hunits x2 = x/2;
  3612.     out->right(x2);
  3613.     x -= x2;
  3614.   }
  3615.   if (is_bold) {
  3616.     int hpos = out->get_hpos();
  3617.     int vpos = out->get_vpos();
  3618.     tprint_reverse_node_list(out, n);
  3619.     out->moveto(hpos, vpos);
  3620.     out->right(bold_offset);
  3621.   }
  3622.   tprint_reverse_node_list(out, n);
  3623.   if (is_constant_spaced)
  3624.     out->right(x);
  3625.   else
  3626.     out->right(track_kern);
  3627. }
  3628.  
  3629. node *make_composite_node(charinfo *s, environment *env)
  3630. {
  3631.   int fontno = env_definite_font(env);
  3632.   if (fontno < 0) {
  3633.     error("no current font");
  3634.     return 0;
  3635.   }
  3636.   assert(fontno < font_table_size && font_table[fontno] != 0);
  3637.   node *n = charinfo_to_node_list(s, env);
  3638.   font_size fs = env->get_font_size();
  3639.   int char_height = env->get_char_height();
  3640.   int char_slant = env->get_char_slant();
  3641.   tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
  3642.                         fontno);
  3643.   if (env->is_composite())
  3644.     tf = tf->get_plain();
  3645.   return new composite_node(n, s, tf);
  3646. }
  3647.  
  3648. node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
  3649. {
  3650.   int fontno = env_definite_font(env);
  3651.   if (fontno < 0) {
  3652.     error("no current font");
  3653.     return 0;
  3654.   }
  3655.   assert(fontno < font_table_size && font_table[fontno] != 0);
  3656.   int fn = fontno;
  3657.   int found = font_table[fontno]->contains(s);
  3658.   if (!found) {
  3659.     if (s->numbered()) {
  3660.       if (!no_error_message)
  3661.     warning(WARN_CHAR, "can't find numbered character %1",
  3662.         s->get_number());
  3663.       return 0;
  3664.     }
  3665.     special_font_list *sf = font_table[fontno]->sf;
  3666.     while (sf != 0 && !found) {
  3667.       fn = sf->n;
  3668.       if (font_table[fn])
  3669.     found = font_table[fn]->contains(s);
  3670.       sf = sf->next;
  3671.     }
  3672.     if (!found) {
  3673.       sf = global_special_fonts;
  3674.       while (sf != 0 && !found) {
  3675.     fn = sf->n;
  3676.     if (font_table[fn])
  3677.       found = font_table[fn]->contains(s);
  3678.     sf = sf->next;
  3679.       }
  3680.     }
  3681.     if (!found
  3682. #if 0    
  3683.     && global_special_fonts == 0 && font_table[fontno]->sf == 0
  3684. #endif
  3685.     ) {
  3686.       for (fn = 0; fn < font_table_size; fn++)
  3687.     if (font_table[fn] 
  3688.         && font_table[fn]->is_special()
  3689.         && font_table[fn]->contains(s)) {
  3690.           found = 1;
  3691.           break;
  3692.         }
  3693.     }
  3694.     if (!found) {
  3695.       if (!no_error_message && s->first_time_not_found()) {
  3696.     unsigned char input_code = s->get_ascii_code();
  3697.     if (input_code != 0) {
  3698.       if (csgraph(input_code))
  3699.         warning(WARN_CHAR, "can't find character `%1'", input_code);
  3700.       else
  3701.         warning(WARN_CHAR, "can't find character with input code %1",
  3702.             int(input_code));
  3703.     }
  3704.     else
  3705.       warning(WARN_CHAR, "can't find special character `%1'",
  3706.           s->nm.contents());
  3707.       }
  3708.       return 0;
  3709.     }
  3710.   }
  3711.   font_size fs = env->get_font_size();
  3712.   int char_height = env->get_char_height();
  3713.   int char_slant = env->get_char_slant();
  3714.   tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
  3715.   if (env->is_composite())
  3716.     tf = tf->get_plain();
  3717.   return new glyph_node(s, tf);
  3718. }
  3719.  
  3720. node *make_node(charinfo *ci, environment *env)
  3721. {
  3722.   switch (ci->get_special_translation()) {
  3723.   case charinfo::TRANSLATE_SPACE:
  3724.     return new space_char_hmotion_node(env->get_space_width());
  3725.   case charinfo::TRANSLATE_DUMMY:
  3726.     return new dummy_node;
  3727.   case charinfo::TRANSLATE_HYPHEN_INDICATOR:
  3728.     error("translation to \\% ignored in this context");
  3729.     break;
  3730.   }
  3731.   charinfo *tem = ci->get_translation();
  3732.   if (tem)
  3733.     ci = tem;
  3734.   macro *mac = ci->get_macro();
  3735.   if (mac)
  3736.     return make_composite_node(ci, env);
  3737.   else
  3738.     return make_glyph_node(ci, env);
  3739. }
  3740.  
  3741. int character_exists(charinfo *ci, environment *env)
  3742. {
  3743.   if (ci->get_special_translation() != charinfo::TRANSLATE_NONE)
  3744.     return 1;
  3745.   charinfo *tem = ci->get_translation();
  3746.   if (tem)
  3747.     ci = tem;
  3748.   if (ci->get_macro())
  3749.     return 1;
  3750.   node *nd = make_glyph_node(ci, env, 1);
  3751.   if (nd) {
  3752.     delete nd;
  3753.     return 1;
  3754.   }
  3755.   return 0;
  3756. }
  3757.  
  3758. node *node::add_char(charinfo *ci, environment *env, hunits *widthp)
  3759. {
  3760.   node *res;
  3761.   switch (ci->get_special_translation()) {
  3762.   case charinfo::TRANSLATE_SPACE:
  3763.     res = new space_char_hmotion_node(env->get_space_width(), this);
  3764.     *widthp += res->width();
  3765.     return res;
  3766.   case charinfo::TRANSLATE_DUMMY:
  3767.     return new dummy_node(this);
  3768.   case charinfo::TRANSLATE_HYPHEN_INDICATOR:
  3769.     return add_discretionary_hyphen();
  3770.   }
  3771.   charinfo *tem = ci->get_translation();
  3772.   if (tem)
  3773.     ci = tem;
  3774.   macro *mac = ci->get_macro();
  3775.   if (mac) {
  3776.     res = make_composite_node(ci, env);
  3777.     if (res) {
  3778.       res->next = this;
  3779.       *widthp += res->width();
  3780.     }
  3781.     else
  3782.       return this;
  3783.   }
  3784.   else {
  3785.     node *gn = make_glyph_node(ci, env);
  3786.     if (gn == 0)
  3787.       return this;
  3788.     else {
  3789.       hunits old_width = width();
  3790.       node *p = gn->merge_self(this);
  3791.       if (p == 0) {
  3792.     *widthp += gn->width();
  3793.     gn->next = this;
  3794.     res = gn;
  3795.       }
  3796.       else {
  3797.     *widthp += p->width() - old_width;
  3798.     res = p;
  3799.       }
  3800.     }
  3801.   }
  3802.   int break_code = 0;
  3803.   if (ci->can_break_before())
  3804.     break_code = 1;
  3805.   if (ci->can_break_after())
  3806.     break_code |= 2;
  3807.   if (break_code) {
  3808.     node *next1 = res->next;
  3809.     res->next = 0;
  3810.     res = new break_char_node(res, break_code, next1);
  3811.   }
  3812.   return res;
  3813. }
  3814.  
  3815.  
  3816. #ifdef __GNUG__
  3817. inline
  3818. #endif
  3819. int same_node(node *n1, node *n2)
  3820. {
  3821.   if (n1 != 0) {
  3822.     if (n2 != 0)
  3823.       return n1->type() == n2->type() && n1->same(n2);
  3824.     else
  3825.       return 0;
  3826.   }
  3827.   else
  3828.     return n2 == 0;
  3829. }
  3830.  
  3831. int same_node_list(node *n1, node *n2)
  3832. {
  3833.   while (n1 && n2) {
  3834.     if (n1->type() != n2->type() || !n1->same(n2))
  3835.       return 0;
  3836.     n1 = n1->next;
  3837.     n2 = n2->next;
  3838.   }
  3839.   return !n1 && !n2;
  3840. }
  3841.  
  3842. int extra_size_node::same(node *nd)
  3843. {
  3844.   return n == ((extra_size_node *)nd)->n;
  3845. }
  3846.  
  3847. const char *extra_size_node::type()
  3848. {
  3849.   return "extra_size_node";
  3850. }
  3851.  
  3852. int vertical_size_node::same(node *nd)
  3853. {
  3854.   return n == ((vertical_size_node *)nd)->n;
  3855. }
  3856.  
  3857. const char *vertical_size_node::type()
  3858. {
  3859.   return "vertical_size_node";
  3860. }
  3861.  
  3862. int hmotion_node::same(node *nd)
  3863. {
  3864.   return n == ((hmotion_node *)nd)->n;
  3865. }
  3866.  
  3867. const char *hmotion_node::type()
  3868. {
  3869.   return "hmotion_node";
  3870. }
  3871.  
  3872. int space_char_hmotion_node::same(node *nd)
  3873. {
  3874.   return n == ((space_char_hmotion_node *)nd)->n;
  3875. }
  3876.  
  3877. const char *space_char_hmotion_node::type()
  3878. {
  3879.   return "space_char_hmotion_node";
  3880. }
  3881.  
  3882. int vmotion_node::same(node *nd)
  3883. {
  3884.   return n == ((vmotion_node *)nd)->n;
  3885. }
  3886.  
  3887. const char *vmotion_node::type()
  3888. {
  3889.   return "vmotion_node";
  3890. }
  3891.  
  3892. int hline_node::same(node *nd)
  3893. {
  3894.   return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
  3895. }
  3896.  
  3897. const char *hline_node::type()
  3898. {
  3899.   return "hline_node";
  3900. }
  3901.  
  3902. int vline_node::same(node *nd)
  3903. {
  3904.   return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
  3905. }
  3906.  
  3907. const char *vline_node::type()
  3908. {
  3909.   return "vline_node";
  3910. }
  3911.  
  3912. int dummy_node::same(node * /*nd*/)
  3913. {
  3914.   return 1;
  3915. }
  3916.  
  3917. const char *dummy_node::type()
  3918. {
  3919.   return "dummy_node";
  3920. }
  3921.  
  3922. int transparent_dummy_node::same(node * /*nd*/)
  3923. {
  3924.   return 1;
  3925. }
  3926.  
  3927. const char *transparent_dummy_node::type()
  3928. {
  3929.   return "transparent_dummy_node";
  3930. }
  3931.  
  3932. int transparent_dummy_node::ends_sentence()
  3933. {
  3934.   return 2;
  3935. }
  3936.  
  3937. int zero_width_node::same(node *nd)
  3938. {
  3939.   return same_node_list(n, ((zero_width_node *)nd)->n);
  3940. }
  3941.  
  3942. const char *zero_width_node::type()
  3943. {
  3944.   return "zero_width_node";
  3945. }
  3946.  
  3947. int italic_corrected_node::same(node *nd)
  3948. {
  3949.   return (x == ((italic_corrected_node *)nd)->x
  3950.       && same_node(n, ((italic_corrected_node *)nd)->n));
  3951. }
  3952.  
  3953. const char *italic_corrected_node::type()
  3954. {
  3955.   return "italic_corrected_node";
  3956. }
  3957.  
  3958.  
  3959. left_italic_corrected_node::left_italic_corrected_node(node *x)
  3960. : n(0), node(x)
  3961. {
  3962. }
  3963.  
  3964. left_italic_corrected_node::~left_italic_corrected_node()
  3965. {
  3966.   delete n;
  3967. }
  3968.  
  3969. node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn)
  3970. {
  3971.   if (n == 0) {
  3972.     hunits lic = gn->left_italic_correction();
  3973.     if (!lic.is_zero()) {
  3974.       x = lic;
  3975.       n = gn;
  3976.       return this;
  3977.     }
  3978.   }
  3979.   else {
  3980.     node *nd = n->merge_glyph_node(gn);
  3981.     if (nd) {
  3982.       n = nd;
  3983.       x = n->left_italic_correction();
  3984.       return this;
  3985.     }
  3986.   }
  3987.   return 0;
  3988. }
  3989.  
  3990. node *left_italic_corrected_node::copy()
  3991. {
  3992.   left_italic_corrected_node *nd = new left_italic_corrected_node;
  3993.   if (n) {
  3994.     nd->n = n->copy();
  3995.     nd->x = x;
  3996.   }
  3997.   return nd;
  3998. }
  3999.  
  4000. void left_italic_corrected_node::tprint(troff_output_file *out)
  4001. {
  4002.   if (n) {
  4003.     out->right(x);
  4004.     n->tprint(out);
  4005.   }
  4006. }
  4007.  
  4008. const char *left_italic_corrected_node::type()
  4009. {
  4010.   return "left_italic_corrected_node";
  4011. }
  4012.  
  4013. int left_italic_corrected_node::same(node *nd)
  4014. {
  4015.   return (x == ((left_italic_corrected_node *)nd)->x
  4016.       && same_node(n, ((left_italic_corrected_node *)nd)->n));
  4017. }
  4018.  
  4019. void left_italic_corrected_node::ascii_print(ascii_output_file *out)
  4020. {
  4021.   if (n)
  4022.     n->ascii_print(out);
  4023. }
  4024.  
  4025. hunits left_italic_corrected_node::width()
  4026. {
  4027.   return n ? n->width() + x : H0;
  4028. }
  4029.  
  4030. void left_italic_corrected_node::vertical_extent(vunits *min, vunits *max)
  4031. {
  4032.   if (n)
  4033.     n->vertical_extent(min, max);
  4034.   else
  4035.     node::vertical_extent(min, max);
  4036. }
  4037.  
  4038. hunits left_italic_corrected_node::skew()
  4039. {
  4040.   return n ? n->skew() + x/2 : H0;
  4041. }
  4042.  
  4043. hunits left_italic_corrected_node::subscript_correction()
  4044. {
  4045.   return n ? n->subscript_correction() : H0;
  4046. }
  4047.  
  4048. hunits left_italic_corrected_node::italic_correction()
  4049. {
  4050.   return n ? n->italic_correction() : H0;
  4051. }
  4052.  
  4053. int left_italic_corrected_node::ends_sentence()
  4054. {
  4055.   return n ? n->ends_sentence() : 0;
  4056. }
  4057.  
  4058. int left_italic_corrected_node::overlaps_horizontally()
  4059. {
  4060.   return n ? n->overlaps_horizontally() : 0;
  4061. }
  4062.  
  4063. int left_italic_corrected_node::overlaps_vertically()
  4064. {
  4065.   return n ? n->overlaps_vertically() : 0;
  4066. }
  4067.  
  4068. node *left_italic_corrected_node::last_char_node()
  4069. {
  4070.   return n ? n->last_char_node() : 0;
  4071. }
  4072.  
  4073. tfont *left_italic_corrected_node::get_tfont()
  4074. {
  4075.   return n ? n->get_tfont() : 0;
  4076. }
  4077.  
  4078. hyphenation_type left_italic_corrected_node::get_hyphenation_type()
  4079. {
  4080.   if (n)
  4081.     return n->get_hyphenation_type();
  4082.   else
  4083.     return HYPHEN_MIDDLE;
  4084. }
  4085.  
  4086. hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail)
  4087. {
  4088.   return n ? n->get_hyphen_list(tail) : tail;
  4089. }
  4090.  
  4091. node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p)
  4092. {
  4093.   if (n) {
  4094.     nd = new left_italic_corrected_node(nd);
  4095.     nd = n->add_self(nd, p);
  4096.     n = 0;
  4097.     delete this;
  4098.   }
  4099.   return nd;
  4100. }
  4101.  
  4102. int left_italic_corrected_node::character_type()
  4103. {
  4104.   return n ? n->character_type() : 0;
  4105. }
  4106.  
  4107. int overstrike_node::same(node *nd)
  4108. {
  4109.   return same_node_list(list, ((overstrike_node *)nd)->list);
  4110. }
  4111.  
  4112. const char *overstrike_node::type()
  4113. {
  4114.   return "overstrike_node";
  4115. }
  4116.  
  4117. int bracket_node::same(node *nd)
  4118. {
  4119.   return same_node_list(list, ((bracket_node *)nd)->list);
  4120. }
  4121.  
  4122. const char *bracket_node::type()
  4123. {
  4124.   return "bracket_node";
  4125. }
  4126.  
  4127. int composite_node::same(node *nd)
  4128. {
  4129.   return ci == ((composite_node *)nd)->ci
  4130.     && same_node_list(n, ((composite_node *)nd)->n);
  4131. }
  4132.  
  4133. const char *composite_node::type()
  4134. {
  4135.   return "composite_node";
  4136. }
  4137.  
  4138. int glyph_node::same(node *nd)
  4139. {
  4140.   return ci == ((glyph_node *)nd)->ci && tf == ((glyph_node *)nd)->tf;
  4141. }
  4142.  
  4143. const char *glyph_node::type()
  4144. {
  4145.   return "glyph_node";
  4146. }
  4147.  
  4148. int ligature_node::same(node *nd)
  4149. {
  4150.   return (same_node(n1, ((ligature_node *)nd)->n1) 
  4151.       && same_node(n2, ((ligature_node *)nd)->n2)
  4152.       && glyph_node::same(nd));
  4153. }
  4154.  
  4155. const char *ligature_node::type()
  4156. {
  4157.   return "ligature_node";
  4158. }
  4159.  
  4160. int kern_pair_node::same(node *nd)
  4161. {
  4162.   return (amount == ((kern_pair_node *)nd)->amount
  4163.       && same_node(n1, ((kern_pair_node *)nd)->n1)
  4164.       && same_node(n2, ((kern_pair_node *)nd)->n2));
  4165. }
  4166.  
  4167. const char *kern_pair_node::type()
  4168. {
  4169.   return "kern_pair_node";
  4170. }
  4171.  
  4172. int dbreak_node::same(node *nd)
  4173. {
  4174.   return (same_node_list(none, ((dbreak_node *)nd)->none)
  4175.       && same_node_list(pre, ((dbreak_node *)nd)->pre)
  4176.       && same_node_list(post, ((dbreak_node *)nd)->post));
  4177. }
  4178.  
  4179. const char *dbreak_node::type()
  4180. {
  4181.   return "dbreak_node";
  4182. }
  4183.  
  4184. int break_char_node::same(node *nd)
  4185. {
  4186.   return (break_code == ((break_char_node *)nd)->break_code
  4187.       && same_node(ch, ((break_char_node *)nd)->ch));
  4188. }
  4189.  
  4190. const char *break_char_node::type()
  4191. {
  4192.   return "break_char_node";
  4193. }
  4194.  
  4195. int line_start_node::same(node * /*nd*/)
  4196. {
  4197.   return 1;
  4198. }
  4199.  
  4200. const char *line_start_node::type()
  4201. {
  4202.   return "line_start_node";
  4203. }
  4204.  
  4205. int space_node::same(node *nd)
  4206. {
  4207.   return n == ((space_node *)nd)->n && set == ((space_node *)nd)->set;
  4208. }
  4209.  
  4210. const char *space_node::type()
  4211. {
  4212.   return "space_node";
  4213. }
  4214.  
  4215. int word_space_node::same(node *nd)
  4216. {
  4217.   return (n == ((word_space_node *)nd)->n
  4218.       && set == ((word_space_node *)nd)->set);
  4219. }
  4220.  
  4221. const char *word_space_node::type()
  4222. {
  4223.   return "word_space_node";
  4224. }
  4225.  
  4226. int unbreakable_space_node::same(node *nd)
  4227. {
  4228.   return (n == ((unbreakable_space_node *)nd)->n
  4229.       && set == ((unbreakable_space_node *)nd)->set);
  4230. }
  4231.  
  4232. const char *unbreakable_space_node::type()
  4233. {
  4234.   return "unbreakable_space_node";
  4235. }
  4236.  
  4237. int diverted_space_node::same(node *nd)
  4238. {
  4239.   return n == ((diverted_space_node *)nd)->n;
  4240. }
  4241.  
  4242. const char *diverted_space_node::type()
  4243. {
  4244.   return "diverted_space_node";
  4245. }
  4246.  
  4247. int diverted_copy_file_node::same(node *nd)
  4248. {
  4249.   return filename == ((diverted_copy_file_node *)nd)->filename;
  4250. }
  4251.  
  4252. const char *diverted_copy_file_node::type()
  4253. {
  4254.   return "diverted_copy_file_node";
  4255. }
  4256.  
  4257. // Grow the font_table so that its size is > n.
  4258.  
  4259. static void grow_font_table(int n)
  4260. {
  4261.   assert(n >= font_table_size);
  4262.   font_info **old_font_table = font_table;
  4263.   int old_font_table_size = font_table_size;
  4264.   font_table_size = font_table_size ? (font_table_size*3)/2 : 10;
  4265.   if (font_table_size <= n)
  4266.     font_table_size = n + 10;
  4267.   font_table = new font_info *[font_table_size];
  4268.   if (old_font_table_size)
  4269.     memcpy(font_table, old_font_table,
  4270.        old_font_table_size*sizeof(font_info *));
  4271.   a_delete old_font_table;
  4272.   for (int i = old_font_table_size; i < font_table_size; i++)
  4273.     font_table[i] = 0;
  4274. }
  4275.  
  4276. dictionary font_translation_dictionary(17);
  4277.  
  4278. static symbol get_font_translation(symbol nm)
  4279. {
  4280.   void *p = font_translation_dictionary.lookup(nm);
  4281.   return p ? symbol((char *)p) : nm;
  4282. }
  4283.  
  4284. dictionary font_dictionary(50);
  4285.  
  4286. static int mount_font_no_translate(int n, symbol name, symbol external_name)
  4287. {
  4288.   assert(n >= 0);
  4289.   // We store the address of this char in font_dictionary to indicate
  4290.   // that we've previously tried to mount the font and failed.
  4291.   static char a_char;
  4292.   font *fm = 0;
  4293.   void *p = font_dictionary.lookup(external_name);
  4294.   if (p == 0) {
  4295.     int not_found;
  4296.     fm = font::load_font(external_name.contents(), ¬_found);
  4297.     if (!fm) {
  4298.       if (not_found)
  4299.     warning(WARN_FONT, "can't find font `%1'", external_name.contents());
  4300.       font_dictionary.lookup(external_name, &a_char);
  4301.       return 0;
  4302.     }
  4303.     font_dictionary.lookup(name, fm);
  4304.   }
  4305.   else if (p == &a_char) {
  4306. #if 0
  4307.     error("invalid font `%1'", external_name.contents());
  4308. #endif
  4309.     return 0;
  4310.   }
  4311.   else
  4312.     fm = (font*)p;
  4313.   if (n >= font_table_size) {
  4314.     if (n - font_table_size > 1000) {
  4315.       error("font position too much larger than first unused position");
  4316.       return 0;
  4317.     }
  4318.     grow_font_table(n);
  4319.   }
  4320.   else if (font_table[n] != 0)
  4321.     delete font_table[n];
  4322.   font_table[n] = new font_info(name, n, external_name, fm);
  4323.   font_family::invalidate_fontno(n);
  4324.   return 1;
  4325. }
  4326.  
  4327. int mount_font(int n, symbol name, symbol external_name)
  4328. {
  4329.   assert(n >= 0);
  4330.   name = get_font_translation(name);
  4331.   if (external_name.is_null())
  4332.     external_name = name;
  4333.   else
  4334.     external_name = get_font_translation(external_name);
  4335.   return mount_font_no_translate(n, name, external_name);
  4336. }
  4337.  
  4338. void mount_style(int n, symbol name)
  4339. {
  4340.   assert(n >= 0);
  4341.   if (n >= font_table_size) {
  4342.     if (n - font_table_size > 1000) {
  4343.       error("font position too much larger than first unused position");
  4344.       return;
  4345.     }
  4346.     grow_font_table(n);
  4347.   }
  4348.   else if (font_table[n] != 0)
  4349.     delete font_table[n];
  4350.   font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0);
  4351.   font_family::invalidate_fontno(n);
  4352. }
  4353.  
  4354. /* global functions */
  4355.  
  4356. void font_translate()
  4357. {
  4358.   symbol from = get_name(1);
  4359.   if (!from.is_null()) {
  4360.     symbol to = get_name();
  4361.     if (to.is_null() || from == to)
  4362.       font_translation_dictionary.remove(from);
  4363.     else
  4364.       font_translation_dictionary.lookup(from, (void *)to.contents());
  4365.   }
  4366.   skip_line();
  4367. }
  4368.  
  4369. void font_position()
  4370. {
  4371.   int n;
  4372.   if (get_integer(&n)) {
  4373.     if (n < 0)
  4374.       error("negative font position");
  4375.     else {
  4376.       symbol internal_name = get_name(1);
  4377.       if (!internal_name.is_null()) {
  4378.     symbol external_name = get_long_name(0);
  4379.     mount_font(n, internal_name, external_name); // ignore error
  4380.       }
  4381.     }
  4382.   }
  4383.   skip_line();
  4384. }
  4385.  
  4386. font_family::font_family(symbol s)
  4387. : nm(s), map_size(10)
  4388. {
  4389.   map = new int[map_size];
  4390.   for (int i = 0; i < map_size; i++)
  4391.     map[i] = -1;
  4392. }
  4393.  
  4394. font_family::~font_family()
  4395. {
  4396.   a_delete map;
  4397. }
  4398.  
  4399. int font_family::make_definite(int i)
  4400. {
  4401.   if (i >= 0) {
  4402.     if (i < map_size && map[i] >= 0)
  4403.       return map[i];
  4404.     else {
  4405.       if (i < font_table_size && font_table[i] != 0) {
  4406.     if (i >= map_size) {
  4407.       int old_map_size = map_size;
  4408.       int *old_map = map;
  4409.       map_size *= 3;
  4410.       map_size /= 2;
  4411.       if (i >= map_size)
  4412.         map_size = i + 10;
  4413.       map = new int[map_size];
  4414.       memcpy(map, old_map, old_map_size*sizeof(int));
  4415.       a_delete old_map;
  4416.       for (int j = old_map_size; j < map_size; j++)
  4417.         map[j] = -1;
  4418.     }
  4419.     if (font_table[i]->is_style()) {
  4420.       symbol sty = font_table[i]->get_name();
  4421.       symbol f = concat(nm, sty);
  4422.       int n;
  4423.       // don't use symbol_fontno, because that might return a style
  4424.       // and because we don't want to translate the name
  4425.       for (n = 0; n < font_table_size; n++)
  4426.         if (font_table[n] != 0 && font_table[n]->is_named(f)
  4427.         && !font_table[n]->is_style())
  4428.           break;
  4429.       if (n >= font_table_size) {
  4430.         n = next_available_font_position();
  4431.         if (!mount_font_no_translate(n, f, f))
  4432.           return -1;
  4433.       }
  4434.       return map[i] = n;
  4435.     }
  4436.     else
  4437.       return map[i] = i;
  4438.       }
  4439.       else
  4440.     return -1;
  4441.     }
  4442.   }
  4443.   else
  4444.     return -1;
  4445. }
  4446.  
  4447. dictionary family_dictionary(5);
  4448.  
  4449. font_family *lookup_family(symbol nm)
  4450. {
  4451.   font_family *f = (font_family *)family_dictionary.lookup(nm);
  4452.   if (!f) {
  4453.     f = new font_family(nm);
  4454.     (void)family_dictionary.lookup(nm, f);
  4455.   }
  4456.   return f;
  4457.  
  4458. void font_family::invalidate_fontno(int n)
  4459. {
  4460.   assert(n >= 0 && n < font_table_size);
  4461.   dictionary_iterator iter(family_dictionary);
  4462.   symbol nm;
  4463.   font_family *fam;
  4464.   while (iter.get(&nm, (void **)&fam)) {
  4465.     int map_size = fam->map_size;
  4466.     if (n < map_size)
  4467.       fam->map[n] = -1;
  4468.     for (int i = 0; i < map_size; i++)
  4469.       if (fam->map[i] == n)
  4470.     fam->map[i] = -1;
  4471.   }
  4472. }
  4473.  
  4474. void style()
  4475. {
  4476.   int n;
  4477.   if (get_integer(&n)) {
  4478.     if (n < 0)
  4479.       error("negative font position");
  4480.     else {
  4481.       symbol internal_name = get_name(1);
  4482.       if (!internal_name.is_null())
  4483.     mount_style(n, internal_name);
  4484.     }
  4485.   }
  4486.   skip_line();
  4487. }
  4488.  
  4489. static int get_fontno()
  4490. {
  4491.   int n;
  4492.   tok.skip();
  4493.   if (tok.delimiter()) {
  4494.     symbol s = get_name(1);
  4495.     if (!s.is_null()) {
  4496.       n = symbol_fontno(s);
  4497.       if (n < 0) {
  4498.     n = next_available_font_position();
  4499.     if (!mount_font(n, s))
  4500.       return -1;
  4501.       }
  4502.       return curenv->get_family()->make_definite(n);
  4503.     }
  4504.   }
  4505.   else if (get_integer(&n)) {
  4506.     if (n < 0 || n >= font_table_size || font_table[n] == 0)
  4507.       error("bad font number");
  4508.     else
  4509.       return curenv->get_family()->make_definite(n);
  4510.   }
  4511.   return -1;
  4512. }
  4513.  
  4514. static int underline_fontno = 2;
  4515.  
  4516. void underline_font()
  4517. {
  4518.   int n = get_fontno();
  4519.   if (n >= 0)
  4520.     underline_fontno = n;
  4521.   skip_line();
  4522. }
  4523.  
  4524. int get_underline_fontno()
  4525. {
  4526.   return underline_fontno;
  4527. }
  4528.     
  4529. static void read_special_fonts(special_font_list **sp)
  4530. {
  4531.   special_font_list *s = *sp;
  4532.   *sp = 0;
  4533.   while (s != 0) {
  4534.     special_font_list *tem = s;
  4535.     s = s->next;
  4536.     delete tem;
  4537.   }
  4538.   special_font_list **p = sp;
  4539.   while (has_arg()) {
  4540.     int i = get_fontno();
  4541.     if (i >= 0) {
  4542.       special_font_list *tem = new special_font_list;
  4543.       tem->n = i;
  4544.       tem->next = 0;
  4545.       *p = tem;
  4546.       p = &(tem->next);
  4547.     }
  4548.   }
  4549. }
  4550.  
  4551. void font_special_request()
  4552. {
  4553.   int n = get_fontno();
  4554.   if (n >= 0)
  4555.     read_special_fonts(&font_table[n]->sf); 
  4556.   skip_line();
  4557. }
  4558.  
  4559.   
  4560. void special_request()
  4561. {
  4562.   read_special_fonts(&global_special_fonts);
  4563.   skip_line();
  4564. }
  4565.  
  4566. int next_available_font_position()
  4567. {
  4568.   int i;
  4569.   for (i = 1; i < font_table_size && font_table[i] != 0; i++)
  4570.     ;
  4571.   return i;
  4572. }
  4573.  
  4574. int symbol_fontno(symbol s)
  4575. {
  4576.   s = get_font_translation(s);
  4577.   for (int i = 0; i < font_table_size; i++)
  4578.     if (font_table[i] != 0 && font_table[i]->is_named(s))
  4579.       return i;
  4580.   return -1;
  4581. }
  4582.  
  4583. int is_good_fontno(int n)
  4584. {
  4585.   return n >= 0 && n < font_table_size && font_table[n] != NULL;
  4586. }
  4587.  
  4588. int get_bold_fontno(int n)
  4589. {
  4590.   if (n >= 0 && n < font_table_size && font_table[n] != 0) {
  4591.     hunits offset;
  4592.     if (font_table[n]->get_bold(&offset))
  4593.       return offset.to_units() + 1;
  4594.     else
  4595.       return 0;
  4596.   }
  4597.   else
  4598.     return 0;
  4599. }
  4600.  
  4601. hunits env_digit_width(environment *env)
  4602. {
  4603.   node *n = make_glyph_node(charset_table['0'], env);
  4604.   if (n) {
  4605.     hunits x = n->width();
  4606.     delete n;
  4607.     return x;
  4608.   }
  4609.   else
  4610.     return H0;
  4611. }
  4612.  
  4613. hunits env_space_width(environment *env)
  4614. {
  4615.   int fn = env_definite_font(env);
  4616.   font_size fs = env->get_font_size();
  4617.   if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
  4618.     return scale(fs.to_units()/3, env->get_space_size(), 12);
  4619.   else
  4620.     return font_table[fn]->get_space_width(fs, env->get_space_size());
  4621. }
  4622.  
  4623. hunits env_sentence_space_width(environment *env)
  4624. {
  4625.   int fn = env_definite_font(env);
  4626.   font_size fs = env->get_font_size();
  4627.   if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
  4628.     return scale(fs.to_units()/3, env->get_sentence_space_size(), 12);
  4629.   else
  4630.     return font_table[fn]->get_space_width(fs, env->get_sentence_space_size());
  4631. }
  4632.  
  4633. hunits env_half_narrow_space_width(environment *env)
  4634. {
  4635.   int fn = env_definite_font(env);
  4636.   font_size fs = env->get_font_size();
  4637.   if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
  4638.     return 0;
  4639.   else
  4640.     return font_table[fn]->get_half_narrow_space_width(fs);
  4641. }
  4642.  
  4643. hunits env_narrow_space_width(environment *env)
  4644. {
  4645.   int fn = env_definite_font(env);
  4646.   font_size fs = env->get_font_size();
  4647.   if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
  4648.     return 0;
  4649.   else
  4650.     return font_table[fn]->get_narrow_space_width(fs);
  4651. }
  4652.  
  4653. void bold_font()
  4654. {
  4655.   int n = get_fontno();
  4656.   if (n >= 0) {
  4657.     if (has_arg()) {
  4658.       if (tok.delimiter()) {
  4659.     int f = get_fontno();
  4660.     if (f >= 0) {
  4661.       units offset;
  4662.       if (has_arg() && get_number(&offset, 'u') && offset >= 1)
  4663.         font_table[f]->set_conditional_bold(n, hunits(offset - 1));
  4664.       else
  4665.         font_table[f]->conditional_unbold(n);
  4666.     }
  4667.       }
  4668.       else {
  4669.     units offset;
  4670.     if (get_number(&offset, 'u') && offset >= 1)
  4671.       font_table[n]->set_bold(hunits(offset - 1));
  4672.     else
  4673.       font_table[n]->unbold();
  4674.       }
  4675.     }
  4676.     else
  4677.       font_table[n]->unbold();
  4678.   }
  4679.   skip_line();
  4680. }
  4681.  
  4682. track_kerning_function::track_kerning_function() : non_zero(0)
  4683. {
  4684. }
  4685.  
  4686. track_kerning_function::track_kerning_function(int min_s, hunits min_a, 
  4687.                            int max_s, hunits max_a)
  4688.      : non_zero(1), 
  4689.      min_size(min_s), min_amount(min_a),
  4690.      max_size(max_s), max_amount(max_a)
  4691. {
  4692. }
  4693.  
  4694. int track_kerning_function::operator==(const track_kerning_function &tk)
  4695. {
  4696.   if (non_zero)
  4697.     return (tk.non_zero
  4698.         && min_size == tk.min_size
  4699.         && min_amount == tk.min_amount
  4700.         && max_size == tk.max_size
  4701.         && max_amount == tk.max_amount);
  4702.   else
  4703.     return !tk.non_zero;
  4704. }
  4705.  
  4706. int track_kerning_function::operator!=(const track_kerning_function &tk)
  4707. {
  4708.   if (non_zero)
  4709.     return (!tk.non_zero
  4710.         || min_size != tk.min_size
  4711.         || min_amount != tk.min_amount
  4712.         || max_size != tk.max_size
  4713.         || max_amount != tk.max_amount);
  4714.   else
  4715.     return tk.non_zero;
  4716. }
  4717.  
  4718. hunits track_kerning_function::compute(int size)
  4719. {
  4720.   if (non_zero) {
  4721.     if (max_size <= min_size)
  4722.       return min_amount;
  4723.     else if (size <= min_size)
  4724.       return min_amount;
  4725.     else if (size >= max_size)
  4726.       return max_amount;
  4727.     else
  4728.       return (scale(max_amount, size - min_size, max_size - min_size)
  4729.           + scale(min_amount, max_size - size, max_size - min_size));
  4730.   }
  4731.   else
  4732.     return H0;
  4733. }
  4734.  
  4735. void track_kern()
  4736. {
  4737.   int n = get_fontno();
  4738.   if (n >= 0) {
  4739.     int min_s, max_s;
  4740.     hunits min_a, max_a;
  4741.     if (has_arg()
  4742.     && get_number(&min_s, 'z')
  4743.     && get_hunits(&min_a, 'p')
  4744.     && get_number(&max_s, 'z')
  4745.     && get_hunits(&max_a, 'p')) {
  4746.       track_kerning_function tk(min_s, min_a, max_s, max_a);
  4747.       font_table[n]->set_track_kern(tk);
  4748.     }
  4749.     else {
  4750.       track_kerning_function tk;
  4751.       font_table[n]->set_track_kern(tk);
  4752.     }
  4753.   }
  4754.   skip_line();
  4755. }
  4756.  
  4757. void constant_space()
  4758. {
  4759.   int n = get_fontno();
  4760.   if (n >= 0) {
  4761.     int x, y;
  4762.     if (!has_arg() || !get_integer(&x))
  4763.       font_table[n]->set_constant_space(CONSTANT_SPACE_NONE);
  4764.     else {
  4765.       if (!has_arg() || !get_number(&y, 'z'))
  4766.     font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x);
  4767.       else
  4768.     font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE, 
  4769.                       scale(y*x,
  4770.                         units_per_inch,
  4771.                         36*72*sizescale));
  4772.     }
  4773.   }
  4774.   skip_line();
  4775. }
  4776.  
  4777. void ligature()
  4778. {
  4779.   int lig;
  4780.   if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2)
  4781.     global_ligature_mode = lig;
  4782.   else
  4783.     global_ligature_mode = 1;
  4784.   skip_line();
  4785. }
  4786.  
  4787. void kern_request()
  4788. {
  4789.   int k;
  4790.   if (has_arg() && get_integer(&k))
  4791.     global_kern_mode = k != 0;
  4792.   else
  4793.     global_kern_mode = 1;
  4794.   skip_line();
  4795. }
  4796.  
  4797. void set_soft_hyphen_char()
  4798. {
  4799.   soft_hyphen_char = get_optional_char();
  4800.   if (!soft_hyphen_char)
  4801.     soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
  4802.   skip_line();
  4803. }
  4804.  
  4805. void init_output()
  4806. {
  4807.   if (suppress_output_flag)
  4808.     the_output = new suppress_output_file;
  4809.   else if (ascii_output_flag)
  4810.     the_output = new ascii_output_file;
  4811.   else
  4812.     the_output = new troff_output_file;
  4813. }
  4814.  
  4815. class next_available_font_position_reg : public reg {
  4816. public:
  4817.   const char *get_string();
  4818. };
  4819.  
  4820. const char *next_available_font_position_reg::get_string()
  4821. {
  4822.   return itoa(next_available_font_position());
  4823. }
  4824.  
  4825. class printing_reg : public reg {
  4826. public:
  4827.   const char *get_string();
  4828. };
  4829.  
  4830. const char *printing_reg::get_string()
  4831. {
  4832.   if (the_output)
  4833.     return the_output->is_printing() ? "1" : "0";
  4834.   else
  4835.     return "0";
  4836. }
  4837.  
  4838. void init_node_requests()
  4839. {
  4840.   init_request("fp", font_position);
  4841.   init_request("sty", style);
  4842.   init_request("cs", constant_space);
  4843.   init_request("bd", bold_font);
  4844.   init_request("uf", underline_font);
  4845.   init_request("lg", ligature);
  4846.   init_request("kern", kern_request);
  4847.   init_request("tkf", track_kern);
  4848.   init_request("special", special_request);
  4849.   init_request("fspecial", font_special_request);
  4850.   init_request("ftr", font_translate);
  4851.   init_request("shc", set_soft_hyphen_char);
  4852.   number_reg_dictionary.define(".fp", new next_available_font_position_reg);
  4853.   number_reg_dictionary.define(".kern",
  4854.                    new constant_int_reg(&global_kern_mode));
  4855.   number_reg_dictionary.define(".lg",
  4856.                    new constant_int_reg(&global_ligature_mode));
  4857.   number_reg_dictionary.define(".P", new printing_reg);
  4858.   soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
  4859. }
  4860.