1114402Sru// -*- C++ -*-
2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
3114402Sru   Free Software Foundation, Inc.
4114402Sru     Written by James Clark (jjc@jclark.com)
5114402Sru
6114402SruThis file is part of groff.
7114402Sru
8114402Srugroff is free software; you can redistribute it and/or modify it under
9114402Sruthe terms of the GNU General Public License as published by the Free
10114402SruSoftware Foundation; either version 2, or (at your option) any later
11114402Sruversion.
12114402Sru
13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
15114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16114402Srufor more details.
17114402Sru
18114402SruYou should have received a copy of the GNU General Public License along
19114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21114402Sru
22151497Sruextern int debug_state;
23151497Sru
24114402Sru#include "troff.h"
25114402Sru
26114402Sru#ifdef HAVE_UNISTD_H
27114402Sru#include <unistd.h>
28114402Sru#endif
29114402Sru
30114402Sru#include "dictionary.h"
31114402Sru#include "hvunits.h"
32151497Sru#include "stringclass.h"
33151497Sru#include "mtsm.h"
34114402Sru#include "env.h"
35114402Sru#include "request.h"
36114402Sru#include "node.h"
37114402Sru#include "token.h"
38151497Sru#include "div.h"
39151497Sru#include "reg.h"
40114402Sru#include "charinfo.h"
41114402Sru#include "font.h"
42114402Sru#include "input.h"
43114402Sru#include "geometry.h"
44114402Sru
45114402Sru#include "nonposix.h"
46114402Sru
47114402Sru#ifdef _POSIX_VERSION
48114402Sru
49114402Sru#include <sys/wait.h>
50114402Sru
51114402Sru#else /* not _POSIX_VERSION */
52114402Sru
53114402Sru/* traditional Unix */
54114402Sru
55114402Sru#define WIFEXITED(s) (((s) & 0377) == 0)
56114402Sru#define WEXITSTATUS(s) (((s) >> 8) & 0377)
57114402Sru#define WTERMSIG(s) ((s) & 0177)
58114402Sru#define WIFSTOPPED(s) (((s) & 0377) == 0177)
59114402Sru#define WSTOPSIG(s) (((s) >> 8) & 0377)
60114402Sru#define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
61114402Sru
62114402Sru#endif /* not _POSIX_VERSION */
63114402Sru
64151497Sru// declarations to avoid friend name injections
65151497Sruclass tfont;
66151497Sruclass tfont_spec;
67151497Srutfont *make_tfont(tfont_spec &);
68151497Sru
69151497Sru
70114402Sru/*
71114402Sru *  how many boundaries of images have been written? Useful for
72114402Sru *  debugging grohtml
73114402Sru */
74114402Sru
75114402Sruint image_no = 0;
76114402Srustatic int suppress_start_page = 0;
77114402Sru
78114402Sru#define STORE_WIDTH 1
79114402Sru
80114402Srusymbol HYPHEN_SYMBOL("hy");
81114402Sru
82114402Sru// Character used when a hyphen is inserted at a line break.
83114402Srustatic charinfo *soft_hyphen_char;
84114402Sru
85114402Sruenum constant_space_type {
86114402Sru  CONSTANT_SPACE_NONE,
87114402Sru  CONSTANT_SPACE_RELATIVE,
88114402Sru  CONSTANT_SPACE_ABSOLUTE
89114402Sru  };
90114402Sru
91114402Srustruct special_font_list {
92114402Sru  int n;
93114402Sru  special_font_list *next;
94114402Sru};
95114402Sru
96114402Sruspecial_font_list *global_special_fonts;
97114402Srustatic int global_ligature_mode = 1;
98114402Srustatic int global_kern_mode = 1;
99114402Sru
100114402Sruclass track_kerning_function {
101114402Sru  int non_zero;
102114402Sru  units min_size;
103114402Sru  hunits min_amount;
104114402Sru  units max_size;
105114402Sru  hunits max_amount;
106114402Srupublic:
107114402Sru  track_kerning_function();
108114402Sru  track_kerning_function(units, hunits, units, hunits);
109114402Sru  int operator==(const track_kerning_function &);
110114402Sru  int operator!=(const track_kerning_function &);
111114402Sru  hunits compute(int point_size);
112114402Sru};
113114402Sru
114114402Sru// embolden fontno when this is the current font
115114402Sru
116114402Srustruct conditional_bold {
117114402Sru  conditional_bold *next;
118114402Sru  int fontno;
119114402Sru  hunits offset;
120114402Sru  conditional_bold(int, hunits, conditional_bold * = 0);
121114402Sru};
122114402Sru
123114402Sruclass font_info {
124114402Sru  tfont *last_tfont;
125114402Sru  int number;
126114402Sru  font_size last_size;
127114402Sru  int last_height;
128114402Sru  int last_slant;
129114402Sru  symbol internal_name;
130114402Sru  symbol external_name;
131114402Sru  font *fm;
132114402Sru  char is_bold;
133114402Sru  hunits bold_offset;
134114402Sru  track_kerning_function track_kern;
135114402Sru  constant_space_type is_constant_spaced;
136114402Sru  units constant_space;
137114402Sru  int last_ligature_mode;
138114402Sru  int last_kern_mode;
139114402Sru  conditional_bold *cond_bold_list;
140114402Sru  void flush();
141114402Srupublic:
142114402Sru  special_font_list *sf;
143151497Sru  font_info(symbol, int, symbol, font *);
144114402Sru  int contains(charinfo *);
145114402Sru  void set_bold(hunits);
146114402Sru  void unbold();
147114402Sru  void set_conditional_bold(int, hunits);
148114402Sru  void conditional_unbold(int);
149114402Sru  void set_track_kern(track_kerning_function &);
150114402Sru  void set_constant_space(constant_space_type, units = 0);
151114402Sru  int is_named(symbol);
152114402Sru  symbol get_name();
153114402Sru  tfont *get_tfont(font_size, int, int, int);
154114402Sru  hunits get_space_width(font_size, int);
155114402Sru  hunits get_narrow_space_width(font_size);
156114402Sru  hunits get_half_narrow_space_width(font_size);
157114402Sru  int get_bold(hunits *);
158114402Sru  int is_special();
159114402Sru  int is_style();
160114402Sru  friend symbol get_font_name(int, environment *);
161151497Sru  friend symbol get_style_name(int);
162114402Sru};
163114402Sru
164114402Sruclass tfont_spec {
165114402Sruprotected:
166114402Sru  symbol name;
167114402Sru  int input_position;
168114402Sru  font *fm;
169114402Sru  font_size size;
170114402Sru  char is_bold;
171114402Sru  char is_constant_spaced;
172114402Sru  int ligature_mode;
173114402Sru  int kern_mode;
174114402Sru  hunits bold_offset;
175114402Sru  hunits track_kern;			// add this to the width
176114402Sru  hunits constant_space_width;
177114402Sru  int height;
178114402Sru  int slant;
179114402Srupublic:
180151497Sru  tfont_spec(symbol, int, font *, font_size, int, int);
181114402Sru  tfont_spec(const tfont_spec &spec) { *this = spec; }
182114402Sru  tfont_spec plain();
183114402Sru  int operator==(const tfont_spec &);
184114402Sru  friend tfont *font_info::get_tfont(font_size fs, int, int, int);
185114402Sru};
186114402Sru
187114402Sruclass tfont : public tfont_spec {
188114402Sru  static tfont *tfont_list;
189114402Sru  tfont *next;
190114402Sru  tfont *plain_version;
191114402Srupublic:
192114402Sru  tfont(tfont_spec &);
193114402Sru  int contains(charinfo *);
194114402Sru  hunits get_width(charinfo *c);
195114402Sru  int get_bold(hunits *);
196114402Sru  int get_constant_space(hunits *);
197114402Sru  hunits get_track_kern();
198114402Sru  tfont *get_plain();
199114402Sru  font_size get_size();
200114402Sru  symbol get_name();
201114402Sru  charinfo *get_lig(charinfo *c1, charinfo *c2);
202114402Sru  int get_kern(charinfo *c1, charinfo *c2, hunits *res);
203114402Sru  int get_input_position();
204114402Sru  int get_character_type(charinfo *);
205114402Sru  int get_height();
206114402Sru  int get_slant();
207114402Sru  vunits get_char_height(charinfo *);
208114402Sru  vunits get_char_depth(charinfo *);
209114402Sru  hunits get_char_skew(charinfo *);
210114402Sru  hunits get_italic_correction(charinfo *);
211114402Sru  hunits get_left_italic_correction(charinfo *);
212114402Sru  hunits get_subscript_correction(charinfo *);
213114402Sru  friend tfont *make_tfont(tfont_spec &);
214114402Sru};
215114402Sru
216114402Sruinline int env_definite_font(environment *env)
217114402Sru{
218114402Sru  return env->get_family()->make_definite(env->get_font());
219114402Sru}
220114402Sru
221114402Sru/* font_info functions */
222114402Sru
223114402Srustatic font_info **font_table = 0;
224114402Srustatic int font_table_size = 0;
225114402Sru
226114402Srufont_info::font_info(symbol nm, int n, symbol enm, font *f)
227114402Sru: last_tfont(0), number(n), last_size(0),
228114402Sru  internal_name(nm), external_name(enm), fm(f),
229114402Sru  is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1),
230114402Sru  last_kern_mode(1), cond_bold_list(0), sf(0)
231114402Sru{
232114402Sru}
233114402Sru
234114402Sruinline int font_info::contains(charinfo *ci)
235114402Sru{
236114402Sru  return fm != 0 && fm->contains(ci->get_index());
237114402Sru}
238114402Sru
239114402Sruinline int font_info::is_special()
240114402Sru{
241114402Sru  return fm != 0 && fm->is_special();
242114402Sru}
243114402Sru
244114402Sruinline int font_info::is_style()
245114402Sru{
246114402Sru  return fm == 0;
247114402Sru}
248114402Sru
249114402Srutfont *make_tfont(tfont_spec &spec)
250114402Sru{
251114402Sru  for (tfont *p = tfont::tfont_list; p; p = p->next)
252114402Sru    if (*p == spec)
253114402Sru      return p;
254114402Sru  return new tfont(spec);
255114402Sru}
256114402Sru
257114402Sru// this is the current_font, fontno is where we found the character,
258114402Sru// presumably a special font
259114402Sru
260114402Srutfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
261114402Sru{
262114402Sru  if (last_tfont == 0 || fs != last_size
263114402Sru      || height != last_height || slant != last_slant
264114402Sru      || global_ligature_mode != last_ligature_mode
265114402Sru      || global_kern_mode != last_kern_mode
266114402Sru      || fontno != number) {
267114402Sru	font_info *f = font_table[fontno];
268114402Sru	tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
269114402Sru	for (conditional_bold *p = cond_bold_list; p; p = p->next)
270114402Sru	  if (p->fontno == fontno) {
271114402Sru	    spec.is_bold = 1;
272114402Sru	    spec.bold_offset = p->offset;
273114402Sru	    break;
274114402Sru	  }
275114402Sru	if (!spec.is_bold && is_bold) {
276114402Sru	  spec.is_bold = 1;
277114402Sru	  spec.bold_offset = bold_offset;
278114402Sru	}
279114402Sru	spec.track_kern = track_kern.compute(fs.to_scaled_points());
280114402Sru	spec.ligature_mode = global_ligature_mode;
281114402Sru	spec.kern_mode = global_kern_mode;
282114402Sru	switch (is_constant_spaced) {
283114402Sru	case CONSTANT_SPACE_NONE:
284114402Sru	  break;
285114402Sru	case CONSTANT_SPACE_ABSOLUTE:
286114402Sru	  spec.is_constant_spaced = 1;
287114402Sru	  spec.constant_space_width = constant_space;
288114402Sru	  break;
289114402Sru	case CONSTANT_SPACE_RELATIVE:
290114402Sru	  spec.is_constant_spaced = 1;
291114402Sru	  spec.constant_space_width
292114402Sru	    = scale(constant_space*fs.to_scaled_points(),
293114402Sru		    units_per_inch,
294114402Sru		    36*72*sizescale);
295114402Sru	  break;
296114402Sru	default:
297114402Sru	  assert(0);
298114402Sru	}
299114402Sru	if (fontno != number)
300114402Sru	  return make_tfont(spec);
301114402Sru	last_tfont = make_tfont(spec);
302114402Sru	last_size = fs;
303114402Sru	last_height = height;
304114402Sru	last_slant = slant;
305114402Sru	last_ligature_mode = global_ligature_mode;
306114402Sru	last_kern_mode = global_kern_mode;
307114402Sru      }
308114402Sru  return last_tfont;
309114402Sru}
310114402Sru
311114402Sruint font_info::get_bold(hunits *res)
312114402Sru{
313114402Sru  if (is_bold) {
314114402Sru    *res = bold_offset;
315114402Sru    return 1;
316114402Sru  }
317114402Sru  else
318114402Sru    return 0;
319114402Sru}
320114402Sru
321114402Sruvoid font_info::unbold()
322114402Sru{
323114402Sru  if (is_bold) {
324114402Sru    is_bold = 0;
325114402Sru    flush();
326114402Sru  }
327114402Sru}
328114402Sru
329114402Sruvoid font_info::set_bold(hunits offset)
330114402Sru{
331114402Sru  if (!is_bold || offset != bold_offset) {
332114402Sru    is_bold = 1;
333114402Sru    bold_offset = offset;
334114402Sru    flush();
335114402Sru  }
336114402Sru}
337114402Sru
338114402Sruvoid font_info::set_conditional_bold(int fontno, hunits offset)
339114402Sru{
340114402Sru  for (conditional_bold *p = cond_bold_list; p; p = p->next)
341114402Sru    if (p->fontno == fontno) {
342114402Sru      if (offset != p->offset) {
343114402Sru	p->offset = offset;
344114402Sru	flush();
345114402Sru      }
346114402Sru      return;
347114402Sru    }
348114402Sru  cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
349114402Sru}
350114402Sru
351114402Sruconditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
352114402Sru: next(x), fontno(f), offset(h)
353114402Sru{
354114402Sru}
355114402Sru
356114402Sruvoid font_info::conditional_unbold(int fontno)
357114402Sru{
358114402Sru  for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
359114402Sru    if ((*p)->fontno == fontno) {
360114402Sru      conditional_bold *tem = *p;
361114402Sru      *p = (*p)->next;
362114402Sru      delete tem;
363114402Sru      flush();
364114402Sru      return;
365114402Sru    }
366114402Sru}
367114402Sru
368114402Sruvoid font_info::set_constant_space(constant_space_type type, units x)
369114402Sru{
370114402Sru  if (type != is_constant_spaced
371114402Sru      || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
372114402Sru    flush();
373114402Sru    is_constant_spaced = type;
374114402Sru    constant_space = x;
375114402Sru  }
376114402Sru}
377114402Sru
378114402Sruvoid font_info::set_track_kern(track_kerning_function &tk)
379114402Sru{
380114402Sru  if (track_kern != tk) {
381114402Sru    track_kern = tk;
382114402Sru    flush();
383114402Sru  }
384114402Sru}
385114402Sru
386114402Sruvoid font_info::flush()
387114402Sru{
388114402Sru  last_tfont = 0;
389114402Sru}
390114402Sru
391114402Sruint font_info::is_named(symbol s)
392114402Sru{
393114402Sru  return internal_name == s;
394114402Sru}
395114402Sru
396114402Srusymbol font_info::get_name()
397114402Sru{
398114402Sru  return internal_name;
399114402Sru}
400114402Sru
401114402Srusymbol get_font_name(int fontno, environment *env)
402114402Sru{
403114402Sru  symbol f = font_table[fontno]->get_name();
404114402Sru  if (font_table[fontno]->is_style()) {
405114402Sru    return concat(env->get_family()->nm, f);
406114402Sru  }
407114402Sru  return f;
408114402Sru}
409114402Sru
410151497Srusymbol get_style_name(int fontno)
411114402Sru{
412151497Sru  if (font_table[fontno]->is_style())
413151497Sru    return font_table[fontno]->get_name();
414151497Sru  else
415151497Sru    return EMPTY_SYMBOL;
416151497Sru}
417151497Sru
418151497Sruhunits font_info::get_space_width(font_size fs, int space_sz)
419151497Sru{
420114402Sru  if (is_constant_spaced == CONSTANT_SPACE_NONE)
421114402Sru    return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
422151497Sru			space_sz, 12);
423114402Sru  else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
424114402Sru    return constant_space;
425114402Sru  else
426114402Sru    return scale(constant_space*fs.to_scaled_points(),
427114402Sru		 units_per_inch, 36*72*sizescale);
428114402Sru}
429114402Sru
430114402Sruhunits font_info::get_narrow_space_width(font_size fs)
431114402Sru{
432114402Sru  charinfo *ci = get_charinfo(symbol("|"));
433114402Sru  if (fm->contains(ci->get_index()))
434114402Sru    return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
435114402Sru  else
436114402Sru    return hunits(fs.to_units()/6);
437114402Sru}
438114402Sru
439114402Sruhunits font_info::get_half_narrow_space_width(font_size fs)
440114402Sru{
441114402Sru  charinfo *ci = get_charinfo(symbol("^"));
442114402Sru  if (fm->contains(ci->get_index()))
443114402Sru    return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
444114402Sru  else
445114402Sru    return hunits(fs.to_units()/12);
446114402Sru}
447114402Sru
448114402Sru/* tfont */
449114402Sru
450114402Srutfont_spec::tfont_spec(symbol nm, int n, font *f,
451114402Sru		       font_size s, int h, int sl)
452114402Sru: name(nm), input_position(n), fm(f), size(s),
453114402Sru  is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
454114402Sru  height(h), slant(sl)
455114402Sru{
456114402Sru  if (height == size.to_scaled_points())
457114402Sru    height = 0;
458114402Sru}
459114402Sru
460114402Sruint tfont_spec::operator==(const tfont_spec &spec)
461114402Sru{
462114402Sru  if (fm == spec.fm
463114402Sru      && size == spec.size
464114402Sru      && input_position == spec.input_position
465114402Sru      && name == spec.name
466114402Sru      && height == spec.height
467114402Sru      && slant == spec.slant
468114402Sru      && (is_bold
469114402Sru	  ? (spec.is_bold && bold_offset == spec.bold_offset)
470114402Sru	  : !spec.is_bold)
471114402Sru      && track_kern == spec.track_kern
472114402Sru      && (is_constant_spaced
473114402Sru	  ? (spec.is_constant_spaced
474114402Sru	     && constant_space_width == spec.constant_space_width)
475114402Sru	  : !spec.is_constant_spaced)
476114402Sru      && ligature_mode == spec.ligature_mode
477114402Sru      && kern_mode == spec.kern_mode)
478114402Sru    return 1;
479114402Sru  else
480114402Sru    return 0;
481114402Sru}
482114402Sru
483114402Srutfont_spec tfont_spec::plain()
484114402Sru{
485114402Sru  return tfont_spec(name, input_position, fm, size, height, slant);
486114402Sru}
487114402Sru
488114402Sruhunits tfont::get_width(charinfo *c)
489114402Sru{
490114402Sru  if (is_constant_spaced)
491114402Sru    return constant_space_width;
492114402Sru  else if (is_bold)
493114402Sru    return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
494114402Sru	    + track_kern + bold_offset);
495114402Sru  else
496114402Sru    return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
497114402Sru	    + track_kern);
498114402Sru}
499114402Sru
500114402Sruvunits tfont::get_char_height(charinfo *c)
501114402Sru{
502114402Sru  vunits v = fm->get_height(c->get_index(), size.to_scaled_points());
503114402Sru  if (height != 0 && height != size.to_scaled_points())
504114402Sru    return scale(v, height, size.to_scaled_points());
505114402Sru  else
506114402Sru    return v;
507114402Sru}
508114402Sru
509114402Sruvunits tfont::get_char_depth(charinfo *c)
510114402Sru{
511114402Sru  vunits v = fm->get_depth(c->get_index(), size.to_scaled_points());
512114402Sru  if (height != 0 && height != size.to_scaled_points())
513114402Sru    return scale(v, height, size.to_scaled_points());
514114402Sru  else
515114402Sru    return v;
516114402Sru}
517114402Sru
518114402Sruhunits tfont::get_char_skew(charinfo *c)
519114402Sru{
520114402Sru  return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant));
521114402Sru}
522114402Sru
523114402Sruhunits tfont::get_italic_correction(charinfo *c)
524114402Sru{
525114402Sru  return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points()));
526114402Sru}
527114402Sru
528114402Sruhunits tfont::get_left_italic_correction(charinfo *c)
529114402Sru{
530114402Sru  return hunits(fm->get_left_italic_correction(c->get_index(),
531114402Sru					       size.to_scaled_points()));
532114402Sru}
533114402Sru
534114402Sruhunits tfont::get_subscript_correction(charinfo *c)
535114402Sru{
536114402Sru  return hunits(fm->get_subscript_correction(c->get_index(),
537114402Sru					     size.to_scaled_points()));
538114402Sru}
539114402Sru
540114402Sruinline int tfont::get_input_position()
541114402Sru{
542114402Sru  return input_position;
543114402Sru}
544114402Sru
545114402Sruinline int tfont::contains(charinfo *ci)
546114402Sru{
547114402Sru  return fm->contains(ci->get_index());
548114402Sru}
549114402Sru
550114402Sruinline int tfont::get_character_type(charinfo *ci)
551114402Sru{
552114402Sru  return fm->get_character_type(ci->get_index());
553114402Sru}
554114402Sru
555114402Sruinline int tfont::get_bold(hunits *res)
556114402Sru{
557114402Sru  if (is_bold) {
558114402Sru    *res = bold_offset;
559114402Sru    return 1;
560114402Sru  }
561114402Sru  else
562114402Sru    return 0;
563114402Sru}
564114402Sru
565114402Sruinline int tfont::get_constant_space(hunits *res)
566114402Sru{
567114402Sru  if (is_constant_spaced) {
568114402Sru    *res = constant_space_width;
569114402Sru    return 1;
570114402Sru  }
571114402Sru  else
572114402Sru    return 0;
573114402Sru}
574114402Sru
575114402Sruinline hunits tfont::get_track_kern()
576114402Sru{
577114402Sru  return track_kern;
578114402Sru}
579114402Sru
580114402Sruinline tfont *tfont::get_plain()
581114402Sru{
582114402Sru  return plain_version;
583114402Sru}
584114402Sru
585114402Sruinline font_size tfont::get_size()
586114402Sru{
587114402Sru  return size;
588114402Sru}
589114402Sru
590114402Sruinline symbol tfont::get_name()
591114402Sru{
592114402Sru  return name;
593114402Sru}
594114402Sru
595114402Sruinline int tfont::get_height()
596114402Sru{
597114402Sru  return height;
598114402Sru}
599114402Sru
600114402Sruinline int tfont::get_slant()
601114402Sru{
602114402Sru  return slant;
603114402Sru}
604114402Sru
605114402Srusymbol SYMBOL_ff("ff");
606114402Srusymbol SYMBOL_fi("fi");
607114402Srusymbol SYMBOL_fl("fl");
608114402Srusymbol SYMBOL_Fi("Fi");
609114402Srusymbol SYMBOL_Fl("Fl");
610114402Sru
611114402Srucharinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
612114402Sru{
613114402Sru  if (ligature_mode == 0)
614114402Sru    return 0;
615114402Sru  charinfo *ci = 0;
616114402Sru  if (c1->get_ascii_code() == 'f') {
617114402Sru    switch (c2->get_ascii_code()) {
618114402Sru    case 'f':
619114402Sru      if (fm->has_ligature(font::LIG_ff))
620114402Sru	ci = get_charinfo(SYMBOL_ff);
621114402Sru      break;
622114402Sru    case 'i':
623114402Sru      if (fm->has_ligature(font::LIG_fi))
624114402Sru	ci = get_charinfo(SYMBOL_fi);
625114402Sru      break;
626114402Sru    case 'l':
627114402Sru      if (fm->has_ligature(font::LIG_fl))
628114402Sru	ci = get_charinfo(SYMBOL_fl);
629114402Sru      break;
630114402Sru    }
631114402Sru  }
632114402Sru  else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
633114402Sru    switch (c2->get_ascii_code()) {
634114402Sru    case 'i':
635114402Sru      if (fm->has_ligature(font::LIG_ffi))
636114402Sru	ci = get_charinfo(SYMBOL_Fi);
637114402Sru      break;
638114402Sru    case 'l':
639114402Sru      if (fm->has_ligature(font::LIG_ffl))
640114402Sru	ci = get_charinfo(SYMBOL_Fl);
641114402Sru      break;
642114402Sru    }
643114402Sru  }
644114402Sru  if (ci != 0 && fm->contains(ci->get_index()))
645114402Sru    return ci;
646114402Sru  return 0;
647114402Sru}
648114402Sru
649114402Sruinline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
650114402Sru{
651114402Sru  if (kern_mode == 0)
652114402Sru    return 0;
653114402Sru  else {
654114402Sru    int n = fm->get_kern(c1->get_index(),
655114402Sru			 c2->get_index(),
656114402Sru			 size.to_scaled_points());
657114402Sru    if (n) {
658114402Sru      *res = hunits(n);
659114402Sru      return 1;
660114402Sru    }
661114402Sru    else
662114402Sru      return 0;
663114402Sru  }
664114402Sru}
665114402Sru
666114402Srutfont *tfont::tfont_list = 0;
667114402Sru
668114402Srutfont::tfont(tfont_spec &spec) : tfont_spec(spec)
669114402Sru{
670114402Sru  next = tfont_list;
671114402Sru  tfont_list = this;
672114402Sru  tfont_spec plain_spec = plain();
673114402Sru  tfont *p;
674114402Sru  for (p = tfont_list; p; p = p->next)
675114402Sru    if (*p == plain_spec) {
676114402Sru      plain_version = p;
677114402Sru      break;
678114402Sru    }
679114402Sru  if (!p)
680114402Sru    plain_version = new tfont(plain_spec);
681114402Sru}
682114402Sru
683114402Sru/* output_file */
684114402Sru
685114402Sruclass real_output_file : public output_file {
686114402Sru#ifndef POPEN_MISSING
687114402Sru  int piped;
688114402Sru#endif
689114402Sru  int printing;        // decision via optional page list
690114402Sru  int output_on;       // \O[0] or \O[1] escape calls
691114402Sru  virtual void really_transparent_char(unsigned char) = 0;
692114402Sru  virtual void really_print_line(hunits x, vunits y, node *n,
693114402Sru				 vunits before, vunits after, hunits width) = 0;
694114402Sru  virtual void really_begin_page(int pageno, vunits page_length) = 0;
695114402Sru  virtual void really_copy_file(hunits x, vunits y, const char *filename);
696114402Sru  virtual void really_put_filename(const char *filename);
697114402Sru  virtual void really_on();
698114402Sru  virtual void really_off();
699151497Srupublic:
700114402Sru  FILE *fp;
701114402Sru  real_output_file();
702114402Sru  ~real_output_file();
703114402Sru  void flush();
704114402Sru  void transparent_char(unsigned char);
705114402Sru  void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
706114402Sru  void begin_page(int pageno, vunits page_length);
707114402Sru  void put_filename(const char *filename);
708114402Sru  void on();
709114402Sru  void off();
710114402Sru  int is_on();
711114402Sru  int is_printing();
712114402Sru  void copy_file(hunits x, vunits y, const char *filename);
713114402Sru};
714114402Sru
715114402Sruclass suppress_output_file : public real_output_file {
716114402Srupublic:
717114402Sru  suppress_output_file();
718114402Sru  void really_transparent_char(unsigned char);
719114402Sru  void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
720114402Sru  void really_begin_page(int pageno, vunits page_length);
721114402Sru};
722114402Sru
723114402Sruclass ascii_output_file : public real_output_file {
724114402Srupublic:
725114402Sru  ascii_output_file();
726114402Sru  void really_transparent_char(unsigned char);
727114402Sru  void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
728114402Sru  void really_begin_page(int pageno, vunits page_length);
729114402Sru  void outc(unsigned char c);
730114402Sru  void outs(const char *s);
731114402Sru};
732114402Sru
733114402Sruvoid ascii_output_file::outc(unsigned char c)
734114402Sru{
735114402Sru  fputc(c, fp);
736114402Sru}
737114402Sru
738114402Sruvoid ascii_output_file::outs(const char *s)
739114402Sru{
740114402Sru  fputc('<', fp);
741114402Sru  if (s)
742114402Sru    fputs(s, fp);
743114402Sru  fputc('>', fp);
744114402Sru}
745114402Sru
746114402Srustruct hvpair;
747114402Sru
748114402Sruclass troff_output_file : public real_output_file {
749114402Sru  units hpos;
750114402Sru  units vpos;
751114402Sru  units output_vpos;
752114402Sru  units output_hpos;
753114402Sru  int force_motion;
754114402Sru  int current_size;
755114402Sru  int current_slant;
756114402Sru  int current_height;
757114402Sru  tfont *current_tfont;
758114402Sru  color *current_fill_color;
759114402Sru  color *current_glyph_color;
760114402Sru  int current_font_number;
761114402Sru  symbol *font_position;
762114402Sru  int nfont_positions;
763114402Sru  enum { TBUF_SIZE = 256 };
764114402Sru  char tbuf[TBUF_SIZE];
765114402Sru  int tbuf_len;
766114402Sru  int tbuf_kern;
767114402Sru  int begun_page;
768151497Sru  int cur_div_level;
769151497Sru  string tag_list;
770114402Sru  void do_motion();
771114402Sru  void put(char c);
772114402Sru  void put(unsigned char c);
773114402Sru  void put(int i);
774114402Sru  void put(unsigned int i);
775114402Sru  void put(const char *s);
776114402Sru  void set_font(tfont *tf);
777114402Sru  void flush_tbuf();
778114402Srupublic:
779114402Sru  troff_output_file();
780114402Sru  ~troff_output_file();
781114402Sru  void trailer(vunits page_length);
782114402Sru  void put_char(charinfo *, tfont *, color *, color *);
783114402Sru  void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits);
784114402Sru  void right(hunits);
785114402Sru  void down(vunits);
786114402Sru  void moveto(hunits, vunits);
787114402Sru  void start_special(tfont *, color *, color *, int = 0);
788114402Sru  void start_special();
789114402Sru  void special_char(unsigned char c);
790114402Sru  void end_special();
791114402Sru  void word_marker();
792114402Sru  void really_transparent_char(unsigned char c);
793114402Sru  void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
794114402Sru  void really_begin_page(int pageno, vunits page_length);
795114402Sru  void really_copy_file(hunits x, vunits y, const char *filename);
796114402Sru  void really_put_filename(const char *filename);
797114402Sru  void really_on();
798114402Sru  void really_off();
799114402Sru  void draw(char, hvpair *, int, font_size, color *, color *);
800114402Sru  void determine_line_limits (char code, hvpair *point, int npoints);
801114402Sru  void check_charinfo(tfont *tf, charinfo *ci);
802114402Sru  void glyph_color(color *c);
803114402Sru  void fill_color(color *c);
804114402Sru  int get_hpos() { return hpos; }
805114402Sru  int get_vpos() { return vpos; }
806151497Sru  void add_to_tag_list(string s);
807114402Sru  friend void space_char_hmotion_node::tprint(troff_output_file *);
808114402Sru  friend void unbreakable_space_node::tprint(troff_output_file *);
809114402Sru};
810114402Sru
811114402Srustatic void put_string(const char *s, FILE *fp)
812114402Sru{
813114402Sru  for (; *s != '\0'; ++s)
814114402Sru    putc(*s, fp);
815114402Sru}
816114402Sru
817114402Sruinline void troff_output_file::put(char c)
818114402Sru{
819114402Sru  putc(c, fp);
820114402Sru}
821114402Sru
822114402Sruinline void troff_output_file::put(unsigned char c)
823114402Sru{
824114402Sru  putc(c, fp);
825114402Sru}
826114402Sru
827114402Sruinline void troff_output_file::put(const char *s)
828114402Sru{
829114402Sru  put_string(s, fp);
830114402Sru}
831114402Sru
832114402Sruinline void troff_output_file::put(int i)
833114402Sru{
834114402Sru  put_string(i_to_a(i), fp);
835114402Sru}
836114402Sru
837114402Sruinline void troff_output_file::put(unsigned int i)
838114402Sru{
839114402Sru  put_string(ui_to_a(i), fp);
840114402Sru}
841114402Sru
842114402Sruvoid troff_output_file::start_special(tfont *tf, color *gcol, color *fcol,
843114402Sru				      int no_init_string)
844114402Sru{
845114402Sru  set_font(tf);
846114402Sru  glyph_color(gcol);
847114402Sru  fill_color(fcol);
848114402Sru  flush_tbuf();
849114402Sru  do_motion();
850114402Sru  if (!no_init_string)
851114402Sru    put("x X ");
852114402Sru}
853114402Sru
854114402Sruvoid troff_output_file::start_special()
855114402Sru{
856114402Sru  flush_tbuf();
857114402Sru  do_motion();
858114402Sru  put("x X ");
859114402Sru}
860114402Sru
861114402Sruvoid troff_output_file::special_char(unsigned char c)
862114402Sru{
863114402Sru  put(c);
864114402Sru  if (c == '\n')
865114402Sru    put('+');
866114402Sru}
867114402Sru
868114402Sruvoid troff_output_file::end_special()
869114402Sru{
870114402Sru  put('\n');
871114402Sru}
872114402Sru
873114402Sruinline void troff_output_file::moveto(hunits h, vunits v)
874114402Sru{
875114402Sru  hpos = h.to_units();
876114402Sru  vpos = v.to_units();
877114402Sru}
878114402Sru
879114402Sruvoid troff_output_file::really_print_line(hunits x, vunits y, node *n,
880114402Sru					  vunits before, vunits after, hunits)
881114402Sru{
882114402Sru  moveto(x, y);
883114402Sru  while (n != 0) {
884151497Sru    // Check whether we should push the current troff state and use
885151497Sru    // the state at the start of the invocation of this diversion.
886151497Sru    if (n->div_nest_level > cur_div_level && n->push_state) {
887151497Sru      state.push_state(n->push_state);
888151497Sru      cur_div_level = n->div_nest_level;
889151497Sru    }
890151497Sru    // Has the current diversion level decreased?  Then we must pop the
891151497Sru    // troff state.
892151497Sru    while (n->div_nest_level < cur_div_level) {
893151497Sru      state.pop_state();
894151497Sru      cur_div_level = n->div_nest_level;
895151497Sru    }
896151497Sru    // Now check whether the state has changed.
897151497Sru    if ((is_on() || n->force_tprint())
898151497Sru	&& (state.changed(n->state) || n->is_tag() || n->is_special)) {
899151497Sru      flush_tbuf();
900151497Sru      do_motion();
901151497Sru      force_motion = 1;
902151497Sru      flush();
903151497Sru      state.flush(fp, n->state, tag_list);
904151497Sru      tag_list = string("");
905151497Sru      flush();
906151497Sru    }
907114402Sru    n->tprint(this);
908114402Sru    n = n->next;
909114402Sru  }
910114402Sru  flush_tbuf();
911114402Sru  // This ensures that transparent throughput will have a more predictable
912114402Sru  // position.
913114402Sru  do_motion();
914114402Sru  force_motion = 1;
915114402Sru  hpos = 0;
916114402Sru  put('n');
917114402Sru  put(before.to_units());
918114402Sru  put(' ');
919114402Sru  put(after.to_units());
920114402Sru  put('\n');
921114402Sru}
922114402Sru
923114402Sruinline void troff_output_file::word_marker()
924114402Sru{
925114402Sru  flush_tbuf();
926114402Sru  if (is_on())
927114402Sru    put('w');
928114402Sru}
929114402Sru
930114402Sruinline void troff_output_file::right(hunits n)
931114402Sru{
932114402Sru  hpos += n.to_units();
933114402Sru}
934114402Sru
935114402Sruinline void troff_output_file::down(vunits n)
936114402Sru{
937114402Sru  vpos += n.to_units();
938114402Sru}
939114402Sru
940114402Sruvoid troff_output_file::do_motion()
941114402Sru{
942114402Sru  if (force_motion) {
943114402Sru    put('V');
944114402Sru    put(vpos);
945114402Sru    put('\n');
946114402Sru    put('H');
947114402Sru    put(hpos);
948114402Sru    put('\n');
949114402Sru  }
950114402Sru  else {
951114402Sru    if (hpos != output_hpos) {
952114402Sru      units n = hpos - output_hpos;
953114402Sru      if (n > 0 && n < hpos) {
954114402Sru	put('h');
955114402Sru	put(n);
956114402Sru      }
957114402Sru      else {
958114402Sru	put('H');
959114402Sru	put(hpos);
960114402Sru      }
961114402Sru      put('\n');
962114402Sru    }
963114402Sru    if (vpos != output_vpos) {
964114402Sru      units n = vpos - output_vpos;
965114402Sru      if (n > 0 && n < vpos) {
966114402Sru	put('v');
967114402Sru	put(n);
968114402Sru      }
969114402Sru      else {
970114402Sru	put('V');
971114402Sru	put(vpos);
972114402Sru      }
973114402Sru      put('\n');
974114402Sru    }
975114402Sru  }
976114402Sru  output_vpos = vpos;
977114402Sru  output_hpos = hpos;
978114402Sru  force_motion = 0;
979114402Sru}
980114402Sru
981114402Sruvoid troff_output_file::flush_tbuf()
982114402Sru{
983114402Sru  if (!is_on()) {
984114402Sru    tbuf_len = 0;
985114402Sru    return;
986114402Sru  }
987114402Sru
988114402Sru  if (tbuf_len == 0)
989114402Sru    return;
990114402Sru  if (tbuf_kern == 0)
991114402Sru    put('t');
992114402Sru  else {
993114402Sru    put('u');
994114402Sru    put(tbuf_kern);
995114402Sru    put(' ');
996114402Sru  }
997114402Sru  check_output_limits(hpos, vpos);
998114402Sru  check_output_limits(hpos, vpos - current_size);
999114402Sru
1000114402Sru  for (int i = 0; i < tbuf_len; i++)
1001114402Sru    put(tbuf[i]);
1002114402Sru  put('\n');
1003114402Sru  tbuf_len = 0;
1004114402Sru}
1005114402Sru
1006114402Sruvoid troff_output_file::check_charinfo(tfont *tf, charinfo *ci)
1007114402Sru{
1008114402Sru  if (!is_on())
1009114402Sru    return;
1010114402Sru
1011114402Sru  int height = tf->get_char_height(ci).to_units();
1012114402Sru  int width = tf->get_width(ci).to_units()
1013114402Sru	      + tf->get_italic_correction(ci).to_units();
1014114402Sru  int depth = tf->get_char_depth(ci).to_units();
1015114402Sru  check_output_limits(output_hpos, output_vpos - height);
1016114402Sru  check_output_limits(output_hpos + width, output_vpos + depth);
1017114402Sru}
1018114402Sru
1019114402Sruvoid troff_output_file::put_char_width(charinfo *ci, tfont *tf,
1020114402Sru				       color *gcol, color *fcol,
1021114402Sru				       hunits w, hunits k)
1022114402Sru{
1023114402Sru  int kk = k.to_units();
1024114402Sru  if (!is_on()) {
1025114402Sru    flush_tbuf();
1026114402Sru    hpos += w.to_units() + kk;
1027114402Sru    return;
1028114402Sru  }
1029114402Sru  set_font(tf);
1030151497Sru  unsigned char c = ci->get_ascii_code();
1031114402Sru  if (c == '\0') {
1032114402Sru    glyph_color(gcol);
1033114402Sru    fill_color(fcol);
1034114402Sru    flush_tbuf();
1035114402Sru    do_motion();
1036114402Sru    check_charinfo(tf, ci);
1037114402Sru    if (ci->numbered()) {
1038114402Sru      put('N');
1039114402Sru      put(ci->get_number());
1040114402Sru    }
1041114402Sru    else {
1042114402Sru      put('C');
1043114402Sru      const char *s = ci->nm.contents();
1044114402Sru      if (s[1] == 0) {
1045114402Sru	put('\\');
1046114402Sru	put(s[0]);
1047114402Sru      }
1048114402Sru      else
1049114402Sru	put(s);
1050114402Sru    }
1051114402Sru    put('\n');
1052114402Sru    hpos += w.to_units() + kk;
1053114402Sru  }
1054114402Sru  else if (tcommand_flag) {
1055114402Sru    if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
1056114402Sru	&& (!gcol || gcol == current_glyph_color)
1057114402Sru	&& (!fcol || fcol == current_fill_color)
1058114402Sru	&& kk == tbuf_kern
1059114402Sru	&& tbuf_len < TBUF_SIZE) {
1060114402Sru      check_charinfo(tf, ci);
1061114402Sru      tbuf[tbuf_len++] = c;
1062114402Sru      output_hpos += w.to_units() + kk;
1063114402Sru      hpos = output_hpos;
1064114402Sru      return;
1065114402Sru    }
1066114402Sru    glyph_color(gcol);
1067114402Sru    fill_color(fcol);
1068114402Sru    flush_tbuf();
1069114402Sru    do_motion();
1070114402Sru    check_charinfo(tf, ci);
1071114402Sru    tbuf[tbuf_len++] = c;
1072114402Sru    output_hpos += w.to_units() + kk;
1073114402Sru    tbuf_kern = kk;
1074114402Sru    hpos = output_hpos;
1075114402Sru  }
1076114402Sru  else {
1077114402Sru    // flush_tbuf();
1078114402Sru    int n = hpos - output_hpos;
1079114402Sru    check_charinfo(tf, ci);
1080114402Sru    // check_output_limits(output_hpos, output_vpos);
1081114402Sru    if (vpos == output_vpos
1082114402Sru	&& (!gcol || gcol == current_glyph_color)
1083114402Sru	&& (!fcol || fcol == current_fill_color)
1084114402Sru	&& n > 0 && n < 100 && !force_motion) {
1085114402Sru      put(char(n/10 + '0'));
1086114402Sru      put(char(n%10 + '0'));
1087114402Sru      put(c);
1088114402Sru      output_hpos = hpos;
1089114402Sru    }
1090114402Sru    else {
1091114402Sru      glyph_color(gcol);
1092114402Sru      fill_color(fcol);
1093114402Sru      do_motion();
1094114402Sru      put('c');
1095114402Sru      put(c);
1096114402Sru    }
1097114402Sru    hpos += w.to_units() + kk;
1098114402Sru  }
1099114402Sru}
1100114402Sru
1101114402Sruvoid troff_output_file::put_char(charinfo *ci, tfont *tf,
1102114402Sru				 color *gcol, color *fcol)
1103114402Sru{
1104114402Sru  flush_tbuf();
1105114402Sru  if (!is_on())
1106114402Sru    return;
1107114402Sru  set_font(tf);
1108151497Sru  unsigned char c = ci->get_ascii_code();
1109114402Sru  if (c == '\0') {
1110114402Sru    glyph_color(gcol);
1111114402Sru    fill_color(fcol);
1112114402Sru    flush_tbuf();
1113114402Sru    do_motion();
1114114402Sru    if (ci->numbered()) {
1115114402Sru      put('N');
1116114402Sru      put(ci->get_number());
1117114402Sru    }
1118114402Sru    else {
1119114402Sru      put('C');
1120114402Sru      const char *s = ci->nm.contents();
1121114402Sru      if (s[1] == 0) {
1122114402Sru	put('\\');
1123114402Sru	put(s[0]);
1124114402Sru      }
1125114402Sru      else
1126114402Sru	put(s);
1127114402Sru    }
1128114402Sru    put('\n');
1129114402Sru  }
1130114402Sru  else {
1131114402Sru    int n = hpos - output_hpos;
1132114402Sru    if (vpos == output_vpos
1133114402Sru	&& (!gcol || gcol == current_glyph_color)
1134114402Sru	&& (!fcol || fcol == current_fill_color)
1135114402Sru	&& n > 0 && n < 100) {
1136114402Sru      put(char(n/10 + '0'));
1137114402Sru      put(char(n%10 + '0'));
1138114402Sru      put(c);
1139114402Sru      output_hpos = hpos;
1140114402Sru    }
1141114402Sru    else {
1142114402Sru      glyph_color(gcol);
1143114402Sru      fill_color(fcol);
1144114402Sru      flush_tbuf();
1145114402Sru      do_motion();
1146114402Sru      put('c');
1147114402Sru      put(c);
1148114402Sru    }
1149114402Sru  }
1150114402Sru}
1151114402Sru
1152114402Sru// set_font calls `flush_tbuf' if necessary.
1153114402Sru
1154114402Sruvoid troff_output_file::set_font(tfont *tf)
1155114402Sru{
1156114402Sru  if (current_tfont == tf)
1157114402Sru    return;
1158114402Sru  flush_tbuf();
1159114402Sru  int n = tf->get_input_position();
1160114402Sru  symbol nm = tf->get_name();
1161114402Sru  if (n >= nfont_positions || font_position[n] != nm) {
1162114402Sru    put("x font ");
1163114402Sru    put(n);
1164114402Sru    put(' ');
1165114402Sru    put(nm.contents());
1166114402Sru    put('\n');
1167114402Sru    if (n >= nfont_positions) {
1168114402Sru      int old_nfont_positions = nfont_positions;
1169114402Sru      symbol *old_font_position = font_position;
1170114402Sru      nfont_positions *= 3;
1171114402Sru      nfont_positions /= 2;
1172114402Sru      if (nfont_positions <= n)
1173114402Sru	nfont_positions = n + 10;
1174114402Sru      font_position = new symbol[nfont_positions];
1175114402Sru      memcpy(font_position, old_font_position,
1176114402Sru	     old_nfont_positions*sizeof(symbol));
1177114402Sru      a_delete old_font_position;
1178114402Sru    }
1179114402Sru    font_position[n] = nm;
1180114402Sru  }
1181114402Sru  if (current_font_number != n) {
1182114402Sru    put('f');
1183114402Sru    put(n);
1184114402Sru    put('\n');
1185114402Sru    current_font_number = n;
1186114402Sru  }
1187114402Sru  int size = tf->get_size().to_scaled_points();
1188114402Sru  if (current_size != size) {
1189114402Sru    put('s');
1190114402Sru    put(size);
1191114402Sru    put('\n');
1192114402Sru    current_size = size;
1193114402Sru  }
1194114402Sru  int slant = tf->get_slant();
1195114402Sru  if (current_slant != slant) {
1196114402Sru    put("x Slant ");
1197114402Sru    put(slant);
1198114402Sru    put('\n');
1199114402Sru    current_slant = slant;
1200114402Sru  }
1201114402Sru  int height = tf->get_height();
1202114402Sru  if (current_height != height) {
1203114402Sru    put("x Height ");
1204114402Sru    put(height == 0 ? current_size : height);
1205114402Sru    put('\n');
1206114402Sru    current_height = height;
1207114402Sru  }
1208114402Sru  current_tfont = tf;
1209114402Sru}
1210114402Sru
1211114402Sru// fill_color calls `flush_tbuf' and `do_motion' if necessary.
1212114402Sru
1213114402Sruvoid troff_output_file::fill_color(color *col)
1214114402Sru{
1215114402Sru  if (!col || current_fill_color == col)
1216114402Sru    return;
1217114402Sru  current_fill_color = col;
1218114402Sru  if (!color_flag)
1219114402Sru    return;
1220114402Sru  flush_tbuf();
1221114402Sru  do_motion();
1222114402Sru  put("DF");
1223114402Sru  unsigned int components[4];
1224114402Sru  color_scheme cs;
1225114402Sru  cs = col->get_components(components);
1226114402Sru  switch (cs) {
1227114402Sru  case DEFAULT:
1228114402Sru    put('d');
1229114402Sru    break;
1230114402Sru  case RGB:
1231114402Sru    put("r ");
1232114402Sru    put(Red);
1233114402Sru    put(' ');
1234114402Sru    put(Green);
1235114402Sru    put(' ');
1236114402Sru    put(Blue);
1237114402Sru    break;
1238114402Sru  case CMY:
1239114402Sru    put("c ");
1240114402Sru    put(Cyan);
1241114402Sru    put(' ');
1242114402Sru    put(Magenta);
1243114402Sru    put(' ');
1244114402Sru    put(Yellow);
1245114402Sru    break;
1246114402Sru  case CMYK:
1247114402Sru    put("k ");
1248114402Sru    put(Cyan);
1249114402Sru    put(' ');
1250114402Sru    put(Magenta);
1251114402Sru    put(' ');
1252114402Sru    put(Yellow);
1253114402Sru    put(' ');
1254114402Sru    put(Black);
1255114402Sru    break;
1256114402Sru  case GRAY:
1257114402Sru    put("g ");
1258114402Sru    put(Gray);
1259114402Sru    break;
1260114402Sru  }
1261114402Sru  put('\n');
1262114402Sru}
1263114402Sru
1264114402Sru// glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1265114402Sru
1266114402Sruvoid troff_output_file::glyph_color(color *col)
1267114402Sru{
1268114402Sru  if (!col || current_glyph_color == col)
1269114402Sru    return;
1270114402Sru  current_glyph_color = col;
1271114402Sru  if (!color_flag)
1272114402Sru    return;
1273114402Sru  flush_tbuf();
1274114402Sru  // grotty doesn't like a color command if the vertical position is zero.
1275114402Sru  do_motion();
1276114402Sru  put("m");
1277114402Sru  unsigned int components[4];
1278114402Sru  color_scheme cs;
1279114402Sru  cs = col->get_components(components);
1280114402Sru  switch (cs) {
1281114402Sru  case DEFAULT:
1282114402Sru    put('d');
1283114402Sru    break;
1284114402Sru  case RGB:
1285114402Sru    put("r ");
1286114402Sru    put(Red);
1287114402Sru    put(' ');
1288114402Sru    put(Green);
1289114402Sru    put(' ');
1290114402Sru    put(Blue);
1291114402Sru    break;
1292114402Sru  case CMY:
1293114402Sru    put("c ");
1294114402Sru    put(Cyan);
1295114402Sru    put(' ');
1296114402Sru    put(Magenta);
1297114402Sru    put(' ');
1298114402Sru    put(Yellow);
1299114402Sru    break;
1300114402Sru  case CMYK:
1301114402Sru    put("k ");
1302114402Sru    put(Cyan);
1303114402Sru    put(' ');
1304114402Sru    put(Magenta);
1305114402Sru    put(' ');
1306114402Sru    put(Yellow);
1307114402Sru    put(' ');
1308114402Sru    put(Black);
1309114402Sru    break;
1310114402Sru  case GRAY:
1311114402Sru    put("g ");
1312114402Sru    put(Gray);
1313114402Sru    break;
1314114402Sru  }
1315114402Sru  put('\n');
1316114402Sru}
1317114402Sru
1318151497Sruvoid troff_output_file::add_to_tag_list(string s)
1319151497Sru{
1320151497Sru  if (tag_list == string(""))
1321151497Sru    tag_list = s;
1322151497Sru  else {
1323151497Sru    tag_list += string("\n");
1324151497Sru    tag_list += s;
1325151497Sru  }
1326151497Sru}
1327151497Sru
1328114402Sru// determine_line_limits - works out the smallest box which will contain
1329114402Sru//			   the entity, code, built from the point array.
1330114402Sruvoid troff_output_file::determine_line_limits(char code, hvpair *point,
1331114402Sru					      int npoints)
1332114402Sru{
1333114402Sru  int i, x, y;
1334114402Sru
1335114402Sru  if (!is_on())
1336114402Sru    return;
1337114402Sru
1338114402Sru  switch (code) {
1339114402Sru  case 'c':
1340114402Sru  case 'C':
1341114402Sru    // only the h field is used when defining a circle
1342114402Sru    check_output_limits(output_hpos,
1343114402Sru			output_vpos - point[0].h.to_units()/2);
1344114402Sru    check_output_limits(output_hpos + point[0].h.to_units(),
1345114402Sru			output_vpos + point[0].h.to_units()/2);
1346114402Sru    break;
1347114402Sru  case 'E':
1348114402Sru  case 'e':
1349114402Sru    check_output_limits(output_hpos,
1350114402Sru			output_vpos - point[0].v.to_units()/2);
1351114402Sru    check_output_limits(output_hpos + point[0].h.to_units(),
1352114402Sru			output_vpos + point[0].v.to_units()/2);
1353114402Sru    break;
1354114402Sru  case 'P':
1355114402Sru  case 'p':
1356114402Sru    x = output_hpos;
1357114402Sru    y = output_vpos;
1358114402Sru    check_output_limits(x, y);
1359114402Sru    for (i = 0; i < npoints; i++) {
1360114402Sru      x += point[i].h.to_units();
1361114402Sru      y += point[i].v.to_units();
1362114402Sru      check_output_limits(x, y);
1363114402Sru    }
1364114402Sru    break;
1365114402Sru  case 't':
1366114402Sru    x = output_hpos;
1367114402Sru    y = output_vpos;
1368114402Sru    for (i = 0; i < npoints; i++) {
1369114402Sru      x += point[i].h.to_units();
1370114402Sru      y += point[i].v.to_units();
1371114402Sru      check_output_limits(x, y);
1372114402Sru    }
1373114402Sru    break;
1374114402Sru  case 'a':
1375114402Sru    double c[2];
1376114402Sru    int p[4];
1377114402Sru    int minx, miny, maxx, maxy;
1378114402Sru    x = output_hpos;
1379114402Sru    y = output_vpos;
1380114402Sru    p[0] = point[0].h.to_units();
1381114402Sru    p[1] = point[0].v.to_units();
1382114402Sru    p[2] = point[1].h.to_units();
1383114402Sru    p[3] = point[1].v.to_units();
1384114402Sru    if (adjust_arc_center(p, c)) {
1385114402Sru      check_output_arc_limits(x, y,
1386114402Sru			      p[0], p[1], p[2], p[3],
1387114402Sru			      c[0], c[1],
1388114402Sru			      &minx, &maxx, &miny, &maxy);
1389114402Sru      check_output_limits(minx, miny);
1390114402Sru      check_output_limits(maxx, maxy);
1391114402Sru      break;
1392114402Sru    }
1393114402Sru    // fall through
1394114402Sru  case 'l':
1395114402Sru    x = output_hpos;
1396114402Sru    y = output_vpos;
1397114402Sru    check_output_limits(x, y);
1398114402Sru    for (i = 0; i < npoints; i++) {
1399114402Sru      x += point[i].h.to_units();
1400114402Sru      y += point[i].v.to_units();
1401114402Sru      check_output_limits(x, y);
1402114402Sru    }
1403114402Sru    break;
1404114402Sru  default:
1405114402Sru    x = output_hpos;
1406114402Sru    y = output_vpos;
1407114402Sru    for (i = 0; i < npoints; i++) {
1408114402Sru      x += point[i].h.to_units();
1409114402Sru      y += point[i].v.to_units();
1410114402Sru      check_output_limits(x, y);
1411114402Sru    }
1412114402Sru  }
1413114402Sru}
1414114402Sru
1415114402Sruvoid troff_output_file::draw(char code, hvpair *point, int npoints,
1416114402Sru			     font_size fsize, color *gcol, color *fcol)
1417114402Sru{
1418114402Sru  int i;
1419114402Sru  glyph_color(gcol);
1420114402Sru  fill_color(fcol);
1421114402Sru  flush_tbuf();
1422114402Sru  do_motion();
1423114402Sru  if (is_on()) {
1424114402Sru    int size = fsize.to_scaled_points();
1425114402Sru    if (current_size != size) {
1426114402Sru      put('s');
1427114402Sru      put(size);
1428114402Sru      put('\n');
1429114402Sru      current_size = size;
1430114402Sru      current_tfont = 0;
1431114402Sru    }
1432114402Sru    put('D');
1433114402Sru    put(code);
1434114402Sru    if (code == 'c') {
1435114402Sru      put(' ');
1436114402Sru      put(point[0].h.to_units());
1437114402Sru    }
1438114402Sru    else
1439114402Sru      for (i = 0; i < npoints; i++) {
1440114402Sru	put(' ');
1441114402Sru	put(point[i].h.to_units());
1442114402Sru	put(' ');
1443114402Sru	put(point[i].v.to_units());
1444114402Sru      }
1445114402Sru    determine_line_limits(code, point, npoints);
1446114402Sru  }
1447114402Sru
1448114402Sru  for (i = 0; i < npoints; i++)
1449114402Sru    output_hpos += point[i].h.to_units();
1450114402Sru  hpos = output_hpos;
1451114402Sru  if (code != 'e') {
1452114402Sru    for (i = 0; i < npoints; i++)
1453114402Sru      output_vpos += point[i].v.to_units();
1454114402Sru    vpos = output_vpos;
1455114402Sru  }
1456114402Sru  if (is_on())
1457114402Sru    put('\n');
1458114402Sru}
1459114402Sru
1460114402Sruvoid troff_output_file::really_on()
1461114402Sru{
1462114402Sru  flush_tbuf();
1463114402Sru  force_motion = 1;
1464114402Sru  do_motion();
1465114402Sru}
1466114402Sru
1467114402Sruvoid troff_output_file::really_off()
1468114402Sru{
1469114402Sru  flush_tbuf();
1470114402Sru}
1471114402Sru
1472114402Sruvoid troff_output_file::really_put_filename(const char *filename)
1473114402Sru{
1474114402Sru  flush_tbuf();
1475114402Sru  put("F ");
1476114402Sru  put(filename);
1477114402Sru  put('\n');
1478114402Sru}
1479114402Sru
1480114402Sruvoid troff_output_file::really_begin_page(int pageno, vunits page_length)
1481114402Sru{
1482114402Sru  flush_tbuf();
1483114402Sru  if (begun_page) {
1484114402Sru    if (page_length > V0) {
1485114402Sru      put('V');
1486114402Sru      put(page_length.to_units());
1487114402Sru      put('\n');
1488114402Sru    }
1489114402Sru  }
1490114402Sru  else
1491114402Sru    begun_page = 1;
1492114402Sru  current_tfont = 0;
1493114402Sru  current_font_number = -1;
1494114402Sru  current_size = 0;
1495114402Sru  // current_height = 0;
1496114402Sru  // current_slant = 0;
1497114402Sru  hpos = 0;
1498114402Sru  vpos = 0;
1499114402Sru  output_hpos = 0;
1500114402Sru  output_vpos = 0;
1501114402Sru  force_motion = 1;
1502114402Sru  for (int i = 0; i < nfont_positions; i++)
1503114402Sru    font_position[i] = NULL_SYMBOL;
1504114402Sru  put('p');
1505114402Sru  put(pageno);
1506114402Sru  put('\n');
1507114402Sru}
1508114402Sru
1509151497Sruvoid troff_output_file::really_copy_file(hunits x, vunits y,
1510151497Sru					 const char *filename)
1511114402Sru{
1512114402Sru  moveto(x, y);
1513114402Sru  flush_tbuf();
1514114402Sru  do_motion();
1515114402Sru  errno = 0;
1516151497Sru  FILE *ifp = include_search_path.open_file_cautious(filename);
1517114402Sru  if (ifp == 0)
1518114402Sru    error("can't open `%1': %2", filename, strerror(errno));
1519114402Sru  else {
1520114402Sru    int c;
1521114402Sru    while ((c = getc(ifp)) != EOF)
1522114402Sru      put(char(c));
1523114402Sru    fclose(ifp);
1524114402Sru  }
1525114402Sru  force_motion = 1;
1526114402Sru  current_size = 0;
1527114402Sru  current_tfont = 0;
1528114402Sru  current_font_number = -1;
1529114402Sru  for (int i = 0; i < nfont_positions; i++)
1530114402Sru    font_position[i] = NULL_SYMBOL;
1531114402Sru}
1532114402Sru
1533114402Sruvoid troff_output_file::really_transparent_char(unsigned char c)
1534114402Sru{
1535114402Sru  put(c);
1536114402Sru}
1537114402Sru
1538114402Srutroff_output_file::~troff_output_file()
1539114402Sru{
1540114402Sru  a_delete font_position;
1541114402Sru}
1542114402Sru
1543114402Sruvoid troff_output_file::trailer(vunits page_length)
1544114402Sru{
1545114402Sru  flush_tbuf();
1546114402Sru  if (page_length > V0) {
1547114402Sru    put("x trailer\n");
1548114402Sru    put('V');
1549114402Sru    put(page_length.to_units());
1550114402Sru    put('\n');
1551114402Sru  }
1552114402Sru  put("x stop\n");
1553114402Sru}
1554114402Sru
1555114402Srutroff_output_file::troff_output_file()
1556114402Sru: current_slant(0), current_height(0), current_fill_color(0),
1557151497Sru  current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0),
1558151497Sru  cur_div_level(0)
1559114402Sru{
1560114402Sru  font_position = new symbol[nfont_positions];
1561114402Sru  put("x T ");
1562114402Sru  put(device);
1563114402Sru  put('\n');
1564114402Sru  put("x res ");
1565114402Sru  put(units_per_inch);
1566114402Sru  put(' ');
1567114402Sru  put(hresolution);
1568114402Sru  put(' ');
1569114402Sru  put(vresolution);
1570114402Sru  put('\n');
1571114402Sru  put("x init\n");
1572114402Sru}
1573114402Sru
1574114402Sru/* output_file */
1575114402Sru
1576114402Sruoutput_file *the_output = 0;
1577114402Sru
1578114402Sruoutput_file::output_file()
1579114402Sru{
1580114402Sru}
1581114402Sru
1582114402Sruoutput_file::~output_file()
1583114402Sru{
1584114402Sru}
1585114402Sru
1586114402Sruvoid output_file::trailer(vunits)
1587114402Sru{
1588114402Sru}
1589114402Sru
1590114402Sruvoid output_file::put_filename(const char *)
1591114402Sru{
1592114402Sru}
1593114402Sru
1594114402Sruvoid output_file::on()
1595114402Sru{
1596114402Sru}
1597114402Sru
1598114402Sruvoid output_file::off()
1599114402Sru{
1600114402Sru}
1601114402Sru
1602114402Srureal_output_file::real_output_file()
1603114402Sru: printing(0), output_on(1)
1604114402Sru{
1605114402Sru#ifndef POPEN_MISSING
1606114402Sru  if (pipe_command) {
1607114402Sru    if ((fp = popen(pipe_command, POPEN_WT)) != 0) {
1608114402Sru      piped = 1;
1609114402Sru      return;
1610114402Sru    }
1611114402Sru    error("pipe open failed: %1", strerror(errno));
1612114402Sru  }
1613114402Sru  piped = 0;
1614114402Sru#endif /* not POPEN_MISSING */
1615114402Sru  fp = stdout;
1616114402Sru}
1617114402Sru
1618114402Srureal_output_file::~real_output_file()
1619114402Sru{
1620114402Sru  if (!fp)
1621114402Sru    return;
1622114402Sru  // To avoid looping, set fp to 0 before calling fatal().
1623114402Sru  if (ferror(fp) || fflush(fp) < 0) {
1624114402Sru    fp = 0;
1625114402Sru    fatal("error writing output file");
1626114402Sru  }
1627114402Sru#ifndef POPEN_MISSING
1628114402Sru  if (piped) {
1629114402Sru    int result = pclose(fp);
1630114402Sru    fp = 0;
1631114402Sru    if (result < 0)
1632114402Sru      fatal("pclose failed");
1633114402Sru    if (!WIFEXITED(result))
1634114402Sru      error("output process `%1' got fatal signal %2",
1635114402Sru	    pipe_command,
1636114402Sru	    WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result));
1637114402Sru    else {
1638114402Sru      int exit_status = WEXITSTATUS(result);
1639114402Sru      if (exit_status != 0)
1640114402Sru	error("output process `%1' exited with status %2",
1641114402Sru	      pipe_command, exit_status);
1642114402Sru    }
1643114402Sru  }
1644114402Sru  else
1645114402Sru#endif /* not POPEN MISSING */
1646114402Sru  if (fclose(fp) < 0) {
1647114402Sru    fp = 0;
1648114402Sru    fatal("error closing output file");
1649114402Sru  }
1650114402Sru}
1651114402Sru
1652114402Sruvoid real_output_file::flush()
1653114402Sru{
1654114402Sru  if (fflush(fp) < 0)
1655114402Sru    fatal("error writing output file");
1656114402Sru}
1657114402Sru
1658114402Sruint real_output_file::is_printing()
1659114402Sru{
1660114402Sru  return printing;
1661114402Sru}
1662114402Sru
1663114402Sruvoid real_output_file::begin_page(int pageno, vunits page_length)
1664114402Sru{
1665114402Sru  printing = in_output_page_list(pageno);
1666114402Sru  if (printing)
1667114402Sru    really_begin_page(pageno, page_length);
1668114402Sru}
1669114402Sru
1670114402Sruvoid real_output_file::copy_file(hunits x, vunits y, const char *filename)
1671114402Sru{
1672114402Sru  if (printing && output_on)
1673114402Sru    really_copy_file(x, y, filename);
1674114402Sru  check_output_limits(x.to_units(), y.to_units());
1675114402Sru}
1676114402Sru
1677114402Sruvoid real_output_file::transparent_char(unsigned char c)
1678114402Sru{
1679114402Sru  if (printing && output_on)
1680114402Sru    really_transparent_char(c);
1681114402Sru}
1682114402Sru
1683114402Sruvoid real_output_file::print_line(hunits x, vunits y, node *n,
1684114402Sru			     vunits before, vunits after, hunits width)
1685114402Sru{
1686114402Sru  if (printing)
1687114402Sru    really_print_line(x, y, n, before, after, width);
1688114402Sru  delete_node_list(n);
1689114402Sru}
1690114402Sru
1691114402Sruvoid real_output_file::really_copy_file(hunits, vunits, const char *)
1692114402Sru{
1693114402Sru  // do nothing
1694114402Sru}
1695114402Sru
1696114402Sruvoid real_output_file::put_filename(const char *filename)
1697114402Sru{
1698114402Sru  really_put_filename(filename);
1699114402Sru}
1700114402Sru
1701114402Sruvoid real_output_file::really_put_filename(const char *)
1702114402Sru{
1703114402Sru}
1704114402Sru
1705114402Sruvoid real_output_file::on()
1706114402Sru{
1707114402Sru  really_on();
1708114402Sru  if (output_on == 0)
1709114402Sru    output_on = 1;
1710114402Sru}
1711114402Sru
1712114402Sruvoid real_output_file::off()
1713114402Sru{
1714114402Sru  really_off();
1715114402Sru  output_on = 0;
1716114402Sru}
1717114402Sru
1718114402Sruint real_output_file::is_on()
1719114402Sru{
1720114402Sru  return output_on;
1721114402Sru}
1722114402Sru
1723114402Sruvoid real_output_file::really_on()
1724114402Sru{
1725114402Sru}
1726114402Sru
1727114402Sruvoid real_output_file::really_off()
1728114402Sru{
1729114402Sru}
1730114402Sru
1731114402Sru/* ascii_output_file */
1732114402Sru
1733114402Sruvoid ascii_output_file::really_transparent_char(unsigned char c)
1734114402Sru{
1735114402Sru  putc(c, fp);
1736114402Sru}
1737114402Sru
1738114402Sruvoid ascii_output_file::really_print_line(hunits, vunits, node *n,
1739114402Sru					  vunits, vunits, hunits)
1740114402Sru{
1741114402Sru  while (n != 0) {
1742114402Sru    n->ascii_print(this);
1743114402Sru    n = n->next;
1744114402Sru  }
1745114402Sru  fputc('\n', fp);
1746114402Sru}
1747114402Sru
1748114402Sruvoid ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
1749114402Sru{
1750114402Sru  fputs("<beginning of page>\n", fp);
1751114402Sru}
1752114402Sru
1753114402Sruascii_output_file::ascii_output_file()
1754114402Sru{
1755114402Sru}
1756114402Sru
1757114402Sru/* suppress_output_file */
1758114402Sru
1759114402Srusuppress_output_file::suppress_output_file()
1760114402Sru{
1761114402Sru}
1762114402Sru
1763114402Sruvoid suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits)
1764114402Sru{
1765114402Sru}
1766114402Sru
1767114402Sruvoid suppress_output_file::really_begin_page(int, vunits)
1768114402Sru{
1769114402Sru}
1770114402Sru
1771114402Sruvoid suppress_output_file::really_transparent_char(unsigned char)
1772114402Sru{
1773114402Sru}
1774114402Sru
1775114402Sru/* glyphs, ligatures, kerns, discretionary breaks */
1776114402Sru
1777114402Sruclass charinfo_node : public node {
1778114402Sruprotected:
1779114402Sru  charinfo *ci;
1780114402Srupublic:
1781151497Sru  charinfo_node(charinfo *, statem *, int, node * = 0);
1782114402Sru  int ends_sentence();
1783114402Sru  int overlaps_vertically();
1784114402Sru  int overlaps_horizontally();
1785114402Sru};
1786114402Sru
1787151497Srucharinfo_node::charinfo_node(charinfo *c, statem *s, int pop, node *x)
1788151497Sru: node(x, s, pop), ci(c)
1789114402Sru{
1790114402Sru}
1791114402Sru
1792114402Sruint charinfo_node::ends_sentence()
1793114402Sru{
1794114402Sru  if (ci->ends_sentence())
1795114402Sru    return 1;
1796114402Sru  else if (ci->transparent())
1797114402Sru    return 2;
1798114402Sru  else
1799114402Sru    return 0;
1800114402Sru}
1801114402Sru
1802114402Sruint charinfo_node::overlaps_horizontally()
1803114402Sru{
1804114402Sru  return ci->overlaps_horizontally();
1805114402Sru}
1806114402Sru
1807114402Sruint charinfo_node::overlaps_vertically()
1808114402Sru{
1809114402Sru  return ci->overlaps_vertically();
1810114402Sru}
1811114402Sru
1812114402Sruclass glyph_node : public charinfo_node {
1813114402Sru  static glyph_node *free_list;
1814114402Sruprotected:
1815114402Sru  tfont *tf;
1816114402Sru  color *gcol;
1817114402Sru  color *fcol;		/* this is needed for grotty */
1818114402Sru#ifdef STORE_WIDTH
1819114402Sru  hunits wid;
1820151497Sru  glyph_node(charinfo *, tfont *, color *, color *, hunits,
1821151497Sru	     statem *, int, node * = 0);
1822114402Sru#endif
1823114402Srupublic:
1824114402Sru  void *operator new(size_t);
1825114402Sru  void operator delete(void *);
1826151497Sru  glyph_node(charinfo *, tfont *, color *, color *,
1827151497Sru	     statem *, int, node * = 0);
1828114402Sru  ~glyph_node() {}
1829114402Sru  node *copy();
1830114402Sru  node *merge_glyph_node(glyph_node *);
1831114402Sru  node *merge_self(node *);
1832114402Sru  hunits width();
1833114402Sru  node *last_char_node();
1834114402Sru  units size();
1835114402Sru  void vertical_extent(vunits *, vunits *);
1836114402Sru  hunits subscript_correction();
1837114402Sru  hunits italic_correction();
1838114402Sru  hunits left_italic_correction();
1839114402Sru  hunits skew();
1840114402Sru  hyphenation_type get_hyphenation_type();
1841114402Sru  tfont *get_tfont();
1842114402Sru  color *get_glyph_color();
1843114402Sru  color *get_fill_color();
1844114402Sru  void tprint(troff_output_file *);
1845114402Sru  void zero_width_tprint(troff_output_file *);
1846114402Sru  hyphen_list *get_hyphen_list(hyphen_list *, int *);
1847114402Sru  node *add_self(node *, hyphen_list **);
1848114402Sru  void ascii_print(ascii_output_file *);
1849114402Sru  void asciify(macro *);
1850114402Sru  int character_type();
1851114402Sru  int same(node *);
1852114402Sru  const char *type();
1853114402Sru  int force_tprint();
1854151497Sru  int is_tag();
1855151497Sru  void debug_node();
1856114402Sru};
1857114402Sru
1858114402Sruglyph_node *glyph_node::free_list = 0;
1859114402Sru
1860114402Sruclass ligature_node : public glyph_node {
1861114402Sru  node *n1;
1862114402Sru  node *n2;
1863114402Sru#ifdef STORE_WIDTH
1864114402Sru  ligature_node(charinfo *, tfont *, color *, color *, hunits,
1865151497Sru		node *, node *, statem *, int, node * = 0);
1866114402Sru#endif
1867114402Srupublic:
1868114402Sru  void *operator new(size_t);
1869114402Sru  void operator delete(void *);
1870114402Sru  ligature_node(charinfo *, tfont *, color *, color *,
1871151497Sru		node *, node *, statem *, int, node * = 0);
1872114402Sru  ~ligature_node();
1873114402Sru  node *copy();
1874114402Sru  node *add_self(node *, hyphen_list **);
1875114402Sru  hyphen_list *get_hyphen_list(hyphen_list *, int *);
1876114402Sru  void ascii_print(ascii_output_file *);
1877114402Sru  void asciify(macro *);
1878114402Sru  int same(node *);
1879114402Sru  const char *type();
1880114402Sru  int force_tprint();
1881151497Sru  int is_tag();
1882114402Sru};
1883114402Sru
1884114402Sruclass kern_pair_node : public node {
1885114402Sru  hunits amount;
1886114402Sru  node *n1;
1887114402Sru  node *n2;
1888114402Srupublic:
1889151497Sru  kern_pair_node(hunits, node *, node *, statem *, int, node * = 0);
1890114402Sru  ~kern_pair_node();
1891114402Sru  node *copy();
1892114402Sru  node *merge_glyph_node(glyph_node *);
1893114402Sru  node *add_self(node *, hyphen_list **);
1894114402Sru  hyphen_list *get_hyphen_list(hyphen_list *, int *);
1895114402Sru  node *add_discretionary_hyphen();
1896114402Sru  hunits width();
1897114402Sru  node *last_char_node();
1898114402Sru  hunits italic_correction();
1899114402Sru  hunits subscript_correction();
1900114402Sru  void tprint(troff_output_file *);
1901114402Sru  hyphenation_type get_hyphenation_type();
1902114402Sru  int ends_sentence();
1903114402Sru  void ascii_print(ascii_output_file *);
1904114402Sru  void asciify(macro *);
1905114402Sru  int same(node *);
1906114402Sru  const char *type();
1907114402Sru  int force_tprint();
1908151497Sru  int is_tag();
1909114402Sru  void vertical_extent(vunits *, vunits *);
1910114402Sru};
1911114402Sru
1912114402Sruclass dbreak_node : public node {
1913114402Sru  node *none;
1914114402Sru  node *pre;
1915114402Sru  node *post;
1916114402Srupublic:
1917151497Sru  dbreak_node(node *, node *, statem *, int, node * = 0);
1918114402Sru  ~dbreak_node();
1919114402Sru  node *copy();
1920114402Sru  node *merge_glyph_node(glyph_node *);
1921114402Sru  node *add_discretionary_hyphen();
1922114402Sru  hunits width();
1923114402Sru  node *last_char_node();
1924114402Sru  hunits italic_correction();
1925114402Sru  hunits subscript_correction();
1926114402Sru  void tprint(troff_output_file *);
1927114402Sru  breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
1928114402Sru			      int is_inner = 0);
1929114402Sru  int nbreaks();
1930114402Sru  int ends_sentence();
1931114402Sru  void split(int, node **, node **);
1932114402Sru  hyphenation_type get_hyphenation_type();
1933114402Sru  void ascii_print(ascii_output_file *);
1934114402Sru  void asciify(macro *);
1935114402Sru  int same(node *);
1936114402Sru  const char *type();
1937114402Sru  int force_tprint();
1938151497Sru  int is_tag();
1939114402Sru};
1940114402Sru
1941114402Sruvoid *glyph_node::operator new(size_t n)
1942114402Sru{
1943114402Sru  assert(n == sizeof(glyph_node));
1944114402Sru  if (!free_list) {
1945114402Sru    const int BLOCK = 1024;
1946114402Sru    free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
1947114402Sru    for (int i = 0; i < BLOCK - 1; i++)
1948114402Sru      free_list[i].next = free_list + i + 1;
1949114402Sru    free_list[BLOCK-1].next = 0;
1950114402Sru  }
1951114402Sru  glyph_node *p = free_list;
1952114402Sru  free_list = (glyph_node *)(free_list->next);
1953114402Sru  p->next = 0;
1954114402Sru  return p;
1955114402Sru}
1956114402Sru
1957114402Sruvoid *ligature_node::operator new(size_t n)
1958114402Sru{
1959114402Sru  return new char[n];
1960114402Sru}
1961114402Sru
1962114402Sruvoid glyph_node::operator delete(void *p)
1963114402Sru{
1964114402Sru  if (p) {
1965114402Sru    ((glyph_node *)p)->next = free_list;
1966114402Sru    free_list = (glyph_node *)p;
1967114402Sru  }
1968114402Sru}
1969114402Sru
1970114402Sruvoid ligature_node::operator delete(void *p)
1971114402Sru{
1972114402Sru  delete[] (char *)p;
1973114402Sru}
1974114402Sru
1975151497Sruglyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc,
1976151497Sru		       statem *s, int pop, node *x)
1977151497Sru: charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc)
1978114402Sru{
1979114402Sru#ifdef STORE_WIDTH
1980114402Sru  wid = tf->get_width(ci);
1981114402Sru#endif
1982114402Sru}
1983114402Sru
1984114402Sru#ifdef STORE_WIDTH
1985114402Sruglyph_node::glyph_node(charinfo *c, tfont *t,
1986151497Sru		       color *gc, color *fc, hunits w,
1987151497Sru		       statem *s, int pop, node *x)
1988151497Sru: charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc), wid(w)
1989114402Sru{
1990114402Sru}
1991114402Sru#endif
1992114402Sru
1993114402Srunode *glyph_node::copy()
1994114402Sru{
1995114402Sru#ifdef STORE_WIDTH
1996151497Sru  return new glyph_node(ci, tf, gcol, fcol, wid, state, div_nest_level);
1997114402Sru#else
1998151497Sru  return new glyph_node(ci, tf, gcol, fcol, state, div_nest_level);
1999114402Sru#endif
2000114402Sru}
2001114402Sru
2002114402Srunode *glyph_node::merge_self(node *nd)
2003114402Sru{
2004114402Sru  return nd->merge_glyph_node(this);
2005114402Sru}
2006114402Sru
2007114402Sruint glyph_node::character_type()
2008114402Sru{
2009114402Sru  return tf->get_character_type(ci);
2010114402Sru}
2011114402Sru
2012114402Srunode *glyph_node::add_self(node *n, hyphen_list **p)
2013114402Sru{
2014114402Sru  assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
2015114402Sru  next = 0;
2016114402Sru  node *nn;
2017114402Sru  if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
2018114402Sru    next = n;
2019114402Sru    nn = this;
2020114402Sru  }
2021114402Sru  if ((*p)->hyphen)
2022114402Sru    nn = nn->add_discretionary_hyphen();
2023114402Sru  hyphen_list *pp = *p;
2024114402Sru  *p = (*p)->next;
2025114402Sru  delete pp;
2026114402Sru  return nn;
2027114402Sru}
2028114402Sru
2029114402Sruunits glyph_node::size()
2030114402Sru{
2031114402Sru  return tf->get_size().to_units();
2032114402Sru}
2033114402Sru
2034114402Sruhyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail, int *count)
2035114402Sru{
2036114402Sru  (*count)++;
2037114402Sru  return new hyphen_list(ci->get_hyphenation_code(), tail);
2038114402Sru}
2039114402Sru
2040114402Srutfont *node::get_tfont()
2041114402Sru{
2042114402Sru  return 0;
2043114402Sru}
2044114402Sru
2045114402Srutfont *glyph_node::get_tfont()
2046114402Sru{
2047114402Sru  return tf;
2048114402Sru}
2049114402Sru
2050114402Srucolor *node::get_glyph_color()
2051114402Sru{
2052114402Sru  return 0;
2053114402Sru}
2054114402Sru
2055114402Srucolor *glyph_node::get_glyph_color()
2056114402Sru{
2057114402Sru  return gcol;
2058114402Sru}
2059114402Sru
2060114402Srucolor *node::get_fill_color()
2061114402Sru{
2062114402Sru  return 0;
2063114402Sru}
2064114402Sru
2065114402Srucolor *glyph_node::get_fill_color()
2066114402Sru{
2067114402Sru  return fcol;
2068114402Sru}
2069114402Sru
2070114402Srunode *node::merge_glyph_node(glyph_node *)
2071114402Sru{
2072114402Sru  return 0;
2073114402Sru}
2074114402Sru
2075114402Srunode *glyph_node::merge_glyph_node(glyph_node *gn)
2076114402Sru{
2077114402Sru  if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) {
2078114402Sru    charinfo *lig;
2079114402Sru    if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
2080114402Sru      node *next1 = next;
2081114402Sru      next = 0;
2082151497Sru      return new ligature_node(lig, tf, gcol, fcol, this, gn, state,
2083151497Sru			       gn->div_nest_level, next1);
2084114402Sru    }
2085114402Sru    hunits kern;
2086114402Sru    if (tf->get_kern(ci, gn->ci, &kern)) {
2087114402Sru      node *next1 = next;
2088114402Sru      next = 0;
2089151497Sru      return new kern_pair_node(kern, this, gn, state,
2090151497Sru				gn->div_nest_level, next1);
2091114402Sru    }
2092114402Sru  }
2093114402Sru  return 0;
2094114402Sru}
2095114402Sru
2096114402Sru#ifdef STORE_WIDTH
2097114402Sruinline
2098114402Sru#endif
2099114402Sruhunits glyph_node::width()
2100114402Sru{
2101114402Sru#ifdef STORE_WIDTH
2102114402Sru  return wid;
2103114402Sru#else
2104114402Sru  return tf->get_width(ci);
2105114402Sru#endif
2106114402Sru}
2107114402Sru
2108114402Srunode *glyph_node::last_char_node()
2109114402Sru{
2110114402Sru  return this;
2111114402Sru}
2112114402Sru
2113114402Sruvoid glyph_node::vertical_extent(vunits *min, vunits *max)
2114114402Sru{
2115114402Sru  *min = -tf->get_char_height(ci);
2116114402Sru  *max = tf->get_char_depth(ci);
2117114402Sru}
2118114402Sru
2119114402Sruhunits glyph_node::skew()
2120114402Sru{
2121114402Sru  return tf->get_char_skew(ci);
2122114402Sru}
2123114402Sru
2124114402Sruhunits glyph_node::subscript_correction()
2125114402Sru{
2126114402Sru  return tf->get_subscript_correction(ci);
2127114402Sru}
2128114402Sru
2129114402Sruhunits glyph_node::italic_correction()
2130114402Sru{
2131114402Sru  return tf->get_italic_correction(ci);
2132114402Sru}
2133114402Sru
2134114402Sruhunits glyph_node::left_italic_correction()
2135114402Sru{
2136114402Sru  return tf->get_left_italic_correction(ci);
2137114402Sru}
2138114402Sru
2139114402Sruhyphenation_type glyph_node::get_hyphenation_type()
2140114402Sru{
2141114402Sru  return HYPHEN_MIDDLE;
2142114402Sru}
2143114402Sru
2144114402Sruvoid glyph_node::ascii_print(ascii_output_file *ascii)
2145114402Sru{
2146114402Sru  unsigned char c = ci->get_ascii_code();
2147114402Sru  if (c != 0)
2148114402Sru    ascii->outc(c);
2149114402Sru  else
2150114402Sru    ascii->outs(ci->nm.contents());
2151114402Sru}
2152114402Sru
2153151497Sruvoid glyph_node::debug_node()
2154151497Sru{
2155151497Sru  unsigned char c = ci->get_ascii_code();
2156151497Sru  fprintf(stderr, "{ %s [", type());
2157151497Sru  if (c)
2158151497Sru    fprintf(stderr, "%c", c);
2159151497Sru  else
2160222083Sbenl    fputs(ci->nm.contents(), stderr);
2161151497Sru  if (push_state)
2162151497Sru    fprintf(stderr, " <push_state>");
2163151497Sru  if (state)
2164151497Sru    state->display_state();
2165151497Sru  fprintf(stderr, " nest level %d", div_nest_level);
2166151497Sru  fprintf(stderr, "]}\n");
2167151497Sru  fflush(stderr);
2168151497Sru}
2169151497Sru
2170114402Sruligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2171151497Sru			     node *gn1, node *gn2, statem *s,
2172151497Sru			     int pop, node *x)
2173151497Sru: glyph_node(c, t, gc, fc, s, pop, x), n1(gn1), n2(gn2)
2174114402Sru{
2175114402Sru}
2176114402Sru
2177114402Sru#ifdef STORE_WIDTH
2178114402Sruligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2179151497Sru			     hunits w, node *gn1, node *gn2, statem *s,
2180151497Sru			     int pop, node *x)
2181151497Sru: glyph_node(c, t, gc, fc, w, s, pop, x), n1(gn1), n2(gn2)
2182114402Sru{
2183114402Sru}
2184114402Sru#endif
2185114402Sru
2186114402Sruligature_node::~ligature_node()
2187114402Sru{
2188114402Sru  delete n1;
2189114402Sru  delete n2;
2190114402Sru}
2191114402Sru
2192114402Srunode *ligature_node::copy()
2193114402Sru{
2194114402Sru#ifdef STORE_WIDTH
2195151497Sru  return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy(),
2196151497Sru			   state, div_nest_level);
2197114402Sru#else
2198151497Sru  return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy(),
2199151497Sru			   state, div_nest_level);
2200114402Sru#endif
2201114402Sru}
2202114402Sru
2203114402Sruvoid ligature_node::ascii_print(ascii_output_file *ascii)
2204114402Sru{
2205114402Sru  n1->ascii_print(ascii);
2206114402Sru  n2->ascii_print(ascii);
2207114402Sru}
2208114402Sru
2209114402Sruhyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail, int *count)
2210114402Sru{
2211114402Sru  hyphen_list *hl = n2->get_hyphen_list(tail, count);
2212114402Sru  return n1->get_hyphen_list(hl, count);
2213114402Sru}
2214114402Sru
2215114402Srunode *ligature_node::add_self(node *n, hyphen_list **p)
2216114402Sru{
2217114402Sru  n = n1->add_self(n, p);
2218114402Sru  n = n2->add_self(n, p);
2219114402Sru  n1 = n2 = 0;
2220114402Sru  delete this;
2221114402Sru  return n;
2222114402Sru}
2223114402Sru
2224151497Srukern_pair_node::kern_pair_node(hunits n, node *first, node *second,
2225151497Sru			       statem* s, int pop, node *x)
2226151497Sru: node(x, s, pop), amount(n), n1(first), n2(second)
2227114402Sru{
2228114402Sru}
2229114402Sru
2230151497Srudbreak_node::dbreak_node(node *n, node *p, statem *s, int pop, node *x)
2231151497Sru: node(x, s, pop), none(n), pre(p), post(0)
2232114402Sru{
2233114402Sru}
2234114402Sru
2235114402Srunode *dbreak_node::merge_glyph_node(glyph_node *gn)
2236114402Sru{
2237114402Sru  glyph_node *gn2 = (glyph_node *)gn->copy();
2238114402Sru  node *new_none = none ? none->merge_glyph_node(gn) : 0;
2239114402Sru  node *new_post = post ? post->merge_glyph_node(gn2) : 0;
2240114402Sru  if (new_none == 0 && new_post == 0) {
2241114402Sru    delete gn2;
2242114402Sru    return 0;
2243114402Sru  }
2244114402Sru  if (new_none != 0)
2245114402Sru    none = new_none;
2246114402Sru  else {
2247114402Sru    gn->next = none;
2248114402Sru    none = gn;
2249114402Sru  }
2250114402Sru  if (new_post != 0)
2251114402Sru    post = new_post;
2252114402Sru  else {
2253114402Sru    gn2->next = post;
2254114402Sru    post = gn2;
2255114402Sru  }
2256114402Sru  return this;
2257114402Sru}
2258114402Sru
2259114402Srunode *kern_pair_node::merge_glyph_node(glyph_node *gn)
2260114402Sru{
2261114402Sru  node *nd = n2->merge_glyph_node(gn);
2262114402Sru  if (nd == 0)
2263114402Sru    return 0;
2264114402Sru  n2 = nd;
2265114402Sru  nd = n2->merge_self(n1);
2266114402Sru  if (nd) {
2267114402Sru    nd->next = next;
2268114402Sru    n1 = 0;
2269114402Sru    n2 = 0;
2270114402Sru    delete this;
2271114402Sru    return nd;
2272114402Sru  }
2273114402Sru  return this;
2274114402Sru}
2275114402Sru
2276114402Sruhunits kern_pair_node::italic_correction()
2277114402Sru{
2278114402Sru  return n2->italic_correction();
2279114402Sru}
2280114402Sru
2281114402Sruhunits kern_pair_node::subscript_correction()
2282114402Sru{
2283114402Sru  return n2->subscript_correction();
2284114402Sru}
2285114402Sru
2286114402Sruvoid kern_pair_node::vertical_extent(vunits *min, vunits *max)
2287114402Sru{
2288114402Sru  n1->vertical_extent(min, max);
2289114402Sru  vunits min2, max2;
2290114402Sru  n2->vertical_extent(&min2, &max2);
2291114402Sru  if (min2 < *min)
2292114402Sru    *min = min2;
2293114402Sru  if (max2 > *max)
2294114402Sru    *max = max2;
2295114402Sru}
2296114402Sru
2297114402Srunode *kern_pair_node::add_discretionary_hyphen()
2298114402Sru{
2299114402Sru  tfont *tf = n2->get_tfont();
2300114402Sru  if (tf) {
2301114402Sru    if (tf->contains(soft_hyphen_char)) {
2302114402Sru      color *gcol = n2->get_glyph_color();
2303114402Sru      color *fcol = n2->get_fill_color();
2304114402Sru      node *next1 = next;
2305114402Sru      next = 0;
2306114402Sru      node *n = copy();
2307151497Sru      glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol,
2308151497Sru				      state, div_nest_level);
2309114402Sru      node *nn = n->merge_glyph_node(gn);
2310114402Sru      if (nn == 0) {
2311114402Sru	gn->next = n;
2312114402Sru	nn = gn;
2313114402Sru      }
2314151497Sru      return new dbreak_node(this, nn, state, div_nest_level, next1);
2315114402Sru    }
2316114402Sru  }
2317114402Sru  return this;
2318114402Sru}
2319114402Sru
2320114402Srukern_pair_node::~kern_pair_node()
2321114402Sru{
2322114402Sru  if (n1 != 0)
2323114402Sru    delete n1;
2324114402Sru  if (n2 != 0)
2325114402Sru    delete n2;
2326114402Sru}
2327114402Sru
2328114402Srudbreak_node::~dbreak_node()
2329114402Sru{
2330114402Sru  delete_node_list(pre);
2331114402Sru  delete_node_list(post);
2332114402Sru  delete_node_list(none);
2333114402Sru}
2334114402Sru
2335114402Srunode *kern_pair_node::copy()
2336114402Sru{
2337151497Sru  return new kern_pair_node(amount, n1->copy(), n2->copy(), state,
2338151497Sru			    div_nest_level);
2339114402Sru}
2340114402Sru
2341114402Srunode *copy_node_list(node *n)
2342114402Sru{
2343114402Sru  node *p = 0;
2344114402Sru  while (n != 0) {
2345114402Sru    node *nn = n->copy();
2346114402Sru    nn->next = p;
2347114402Sru    p = nn;
2348114402Sru    n = n->next;
2349114402Sru  }
2350114402Sru  while (p != 0) {
2351114402Sru    node *pp = p->next;
2352114402Sru    p->next = n;
2353114402Sru    n = p;
2354114402Sru    p = pp;
2355114402Sru  }
2356114402Sru  return n;
2357114402Sru}
2358114402Sru
2359114402Sruvoid delete_node_list(node *n)
2360114402Sru{
2361114402Sru  while (n != 0) {
2362114402Sru    node *tem = n;
2363114402Sru    n = n->next;
2364114402Sru    delete tem;
2365114402Sru  }
2366114402Sru}
2367114402Sru
2368114402Srunode *dbreak_node::copy()
2369114402Sru{
2370151497Sru  dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre),
2371151497Sru				   state, div_nest_level);
2372114402Sru  p->post = copy_node_list(post);
2373114402Sru  return p;
2374114402Sru}
2375114402Sru
2376114402Sruhyphen_list *node::get_hyphen_list(hyphen_list *tail, int *)
2377114402Sru{
2378114402Sru  return tail;
2379114402Sru}
2380114402Sru
2381114402Sruhyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail, int *count)
2382114402Sru{
2383114402Sru  hyphen_list *hl = n2->get_hyphen_list(tail, count);
2384114402Sru  return n1->get_hyphen_list(hl, count);
2385114402Sru}
2386114402Sru
2387114402Sruclass hyphen_inhibitor_node : public node {
2388114402Srupublic:
2389151497Sru  hyphen_inhibitor_node(node * = 0);
2390114402Sru  node *copy();
2391114402Sru  int same(node *);
2392114402Sru  const char *type();
2393114402Sru  int force_tprint();
2394151497Sru  int is_tag();
2395114402Sru  hyphenation_type get_hyphenation_type();
2396114402Sru};
2397114402Sru
2398114402Sruhyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd)
2399114402Sru{
2400114402Sru}
2401114402Sru
2402114402Srunode *hyphen_inhibitor_node::copy()
2403114402Sru{
2404114402Sru  return new hyphen_inhibitor_node;
2405114402Sru}
2406114402Sru
2407114402Sruint hyphen_inhibitor_node::same(node *)
2408114402Sru{
2409114402Sru  return 1;
2410114402Sru}
2411114402Sru
2412114402Sruconst char *hyphen_inhibitor_node::type()
2413114402Sru{
2414114402Sru  return "hyphen_inhibitor_node";
2415114402Sru}
2416114402Sru
2417114402Sruint hyphen_inhibitor_node::force_tprint()
2418114402Sru{
2419114402Sru  return 0;
2420114402Sru}
2421114402Sru
2422151497Sruint hyphen_inhibitor_node::is_tag()
2423151497Sru{
2424151497Sru  return 0;
2425151497Sru}
2426151497Sru
2427114402Sruhyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
2428114402Sru{
2429114402Sru  return HYPHEN_INHIBIT;
2430114402Sru}
2431114402Sru
2432114402Sru/* add_discretionary_hyphen methods */
2433114402Sru
2434114402Srunode *dbreak_node::add_discretionary_hyphen()
2435114402Sru{
2436114402Sru  if (post)
2437114402Sru    post = post->add_discretionary_hyphen();
2438114402Sru  if (none)
2439114402Sru    none = none->add_discretionary_hyphen();
2440114402Sru  return this;
2441114402Sru}
2442114402Sru
2443114402Srunode *node::add_discretionary_hyphen()
2444114402Sru{
2445114402Sru  tfont *tf = get_tfont();
2446114402Sru  if (!tf)
2447114402Sru    return new hyphen_inhibitor_node(this);
2448114402Sru  if (tf->contains(soft_hyphen_char)) {
2449114402Sru    color *gcol = get_glyph_color();
2450114402Sru    color *fcol = get_fill_color();
2451114402Sru    node *next1 = next;
2452114402Sru    next = 0;
2453114402Sru    node *n = copy();
2454151497Sru    glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol,
2455151497Sru				    state, div_nest_level);
2456114402Sru    node *n1 = n->merge_glyph_node(gn);
2457114402Sru    if (n1 == 0) {
2458114402Sru      gn->next = n;
2459114402Sru      n1 = gn;
2460114402Sru    }
2461151497Sru    return new dbreak_node(this, n1, state, div_nest_level, next1);
2462114402Sru  }
2463114402Sru  return this;
2464114402Sru}
2465114402Sru
2466114402Srunode *node::merge_self(node *)
2467114402Sru{
2468114402Sru  return 0;
2469114402Sru}
2470114402Sru
2471114402Srunode *node::add_self(node *n, hyphen_list ** /*p*/)
2472114402Sru{
2473114402Sru  next = n;
2474114402Sru  return this;
2475114402Sru}
2476114402Sru
2477114402Srunode *kern_pair_node::add_self(node *n, hyphen_list **p)
2478114402Sru{
2479114402Sru  n = n1->add_self(n, p);
2480114402Sru  n = n2->add_self(n, p);
2481114402Sru  n1 = n2 = 0;
2482114402Sru  delete this;
2483114402Sru  return n;
2484114402Sru}
2485114402Sru
2486114402Sruhunits node::width()
2487114402Sru{
2488114402Sru  return H0;
2489114402Sru}
2490114402Sru
2491114402Srunode *node::last_char_node()
2492114402Sru{
2493114402Sru  return 0;
2494114402Sru}
2495114402Sru
2496114402Sruint node::force_tprint()
2497114402Sru{
2498114402Sru  return 0;
2499114402Sru}
2500114402Sru
2501151497Sruint node::is_tag()
2502151497Sru{
2503151497Sru  return 0;
2504151497Sru}
2505151497Sru
2506114402Sruhunits hmotion_node::width()
2507114402Sru{
2508114402Sru  return n;
2509114402Sru}
2510114402Sru
2511114402Sruunits node::size()
2512114402Sru{
2513114402Sru  return points_to_units(10);
2514114402Sru}
2515114402Sru
2516151497Sruvoid node::debug_node()
2517151497Sru{
2518151497Sru  fprintf(stderr, "{ %s ", type());
2519151497Sru  if (push_state)
2520151497Sru    fprintf(stderr, " <push_state>");
2521151497Sru  if (state)
2522151497Sru    fprintf(stderr, " <state>");
2523151497Sru  fprintf(stderr, " nest level %d", div_nest_level);
2524151497Sru  fprintf(stderr, " }\n");
2525151497Sru  fflush(stderr);
2526151497Sru}
2527151497Sru
2528151497Sruvoid node::debug_node_list()
2529151497Sru{
2530151497Sru  node *n = next;
2531151497Sru
2532151497Sru  debug_node();
2533151497Sru  while (n != 0) {
2534151497Sru    n->debug_node();
2535151497Sru    n = n->next;
2536151497Sru  }
2537151497Sru}
2538151497Sru
2539114402Sruhunits kern_pair_node::width()
2540114402Sru{
2541114402Sru  return n1->width() + n2->width() + amount;
2542114402Sru}
2543114402Sru
2544114402Srunode *kern_pair_node::last_char_node()
2545114402Sru{
2546114402Sru  node *nd = n2->last_char_node();
2547114402Sru  if (nd)
2548114402Sru    return nd;
2549114402Sru  return n1->last_char_node();
2550114402Sru}
2551114402Sru
2552114402Sruhunits dbreak_node::width()
2553114402Sru{
2554114402Sru  hunits x = H0;
2555114402Sru  for (node *n = none; n != 0; n = n->next)
2556114402Sru    x += n->width();
2557114402Sru  return x;
2558114402Sru}
2559114402Sru
2560114402Srunode *dbreak_node::last_char_node()
2561114402Sru{
2562114402Sru  for (node *n = none; n; n = n->next) {
2563151497Sru    node *last_node = n->last_char_node();
2564151497Sru    if (last_node)
2565151497Sru      return last_node;
2566114402Sru  }
2567114402Sru  return 0;
2568114402Sru}
2569114402Sru
2570114402Sruhunits dbreak_node::italic_correction()
2571114402Sru{
2572114402Sru  return none ? none->italic_correction() : H0;
2573114402Sru}
2574114402Sru
2575114402Sruhunits dbreak_node::subscript_correction()
2576114402Sru{
2577114402Sru  return none ? none->subscript_correction() : H0;
2578114402Sru}
2579114402Sru
2580114402Sruclass italic_corrected_node : public node {
2581114402Sru  node *n;
2582114402Sru  hunits x;
2583114402Srupublic:
2584151497Sru  italic_corrected_node(node *, hunits, statem *, int, node * = 0);
2585114402Sru  ~italic_corrected_node();
2586114402Sru  node *copy();
2587114402Sru  void ascii_print(ascii_output_file *);
2588114402Sru  void asciify(macro *);
2589114402Sru  hunits width();
2590114402Sru  node *last_char_node();
2591114402Sru  void vertical_extent(vunits *, vunits *);
2592114402Sru  int ends_sentence();
2593114402Sru  int overlaps_horizontally();
2594114402Sru  int overlaps_vertically();
2595114402Sru  int same(node *);
2596114402Sru  hyphenation_type get_hyphenation_type();
2597114402Sru  tfont *get_tfont();
2598114402Sru  hyphen_list *get_hyphen_list(hyphen_list *, int *);
2599114402Sru  int character_type();
2600114402Sru  void tprint(troff_output_file *);
2601114402Sru  hunits subscript_correction();
2602114402Sru  hunits skew();
2603114402Sru  node *add_self(node *, hyphen_list **);
2604114402Sru  const char *type();
2605114402Sru  int force_tprint();
2606151497Sru  int is_tag();
2607114402Sru};
2608114402Sru
2609151497Srunode *node::add_italic_correction(hunits *wd)
2610114402Sru{
2611114402Sru  hunits ic = italic_correction();
2612114402Sru  if (ic.is_zero())
2613114402Sru    return this;
2614114402Sru  else {
2615114402Sru    node *next1 = next;
2616114402Sru    next = 0;
2617151497Sru    *wd += ic;
2618151497Sru    return new italic_corrected_node(this, ic, state, div_nest_level, next1);
2619114402Sru  }
2620114402Sru}
2621114402Sru
2622151497Sruitalic_corrected_node::italic_corrected_node(node *nn, hunits xx, statem *s,
2623151497Sru					     int pop, node *p)
2624151497Sru: node(p, s, pop), n(nn), x(xx)
2625114402Sru{
2626114402Sru  assert(n != 0);
2627114402Sru}
2628114402Sru
2629114402Sruitalic_corrected_node::~italic_corrected_node()
2630114402Sru{
2631114402Sru  delete n;
2632114402Sru}
2633114402Sru
2634114402Srunode *italic_corrected_node::copy()
2635114402Sru{
2636151497Sru  return new italic_corrected_node(n->copy(), x, state, div_nest_level);
2637114402Sru}
2638114402Sru
2639114402Sruhunits italic_corrected_node::width()
2640114402Sru{
2641114402Sru  return n->width() + x;
2642114402Sru}
2643114402Sru
2644114402Sruvoid italic_corrected_node::vertical_extent(vunits *min, vunits *max)
2645114402Sru{
2646114402Sru  n->vertical_extent(min, max);
2647114402Sru}
2648114402Sru
2649114402Sruvoid italic_corrected_node::tprint(troff_output_file *out)
2650114402Sru{
2651114402Sru  n->tprint(out);
2652114402Sru  out->right(x);
2653114402Sru}
2654114402Sru
2655114402Sruhunits italic_corrected_node::skew()
2656114402Sru{
2657114402Sru  return n->skew() - x/2;
2658114402Sru}
2659114402Sru
2660114402Sruhunits italic_corrected_node::subscript_correction()
2661114402Sru{
2662114402Sru  return n->subscript_correction() - x;
2663114402Sru}
2664114402Sru
2665114402Sruvoid italic_corrected_node::ascii_print(ascii_output_file *out)
2666114402Sru{
2667114402Sru  n->ascii_print(out);
2668114402Sru}
2669114402Sru
2670114402Sruint italic_corrected_node::ends_sentence()
2671114402Sru{
2672114402Sru  return n->ends_sentence();
2673114402Sru}
2674114402Sru
2675114402Sruint italic_corrected_node::overlaps_horizontally()
2676114402Sru{
2677114402Sru  return n->overlaps_horizontally();
2678114402Sru}
2679114402Sru
2680114402Sruint italic_corrected_node::overlaps_vertically()
2681114402Sru{
2682114402Sru  return n->overlaps_vertically();
2683114402Sru}
2684114402Sru
2685114402Srunode *italic_corrected_node::last_char_node()
2686114402Sru{
2687114402Sru  return n->last_char_node();
2688114402Sru}
2689114402Sru
2690114402Srutfont *italic_corrected_node::get_tfont()
2691114402Sru{
2692114402Sru  return n->get_tfont();
2693114402Sru}
2694114402Sru
2695114402Sruhyphenation_type italic_corrected_node::get_hyphenation_type()
2696114402Sru{
2697114402Sru  return n->get_hyphenation_type();
2698114402Sru}
2699114402Sru
2700114402Srunode *italic_corrected_node::add_self(node *nd, hyphen_list **p)
2701114402Sru{
2702114402Sru  nd = n->add_self(nd, p);
2703114402Sru  hunits not_interested;
2704114402Sru  nd = nd->add_italic_correction(&not_interested);
2705114402Sru  n = 0;
2706114402Sru  delete this;
2707114402Sru  return nd;
2708114402Sru}
2709114402Sru
2710114402Sruhyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail,
2711114402Sru						    int *count)
2712114402Sru{
2713114402Sru  return n->get_hyphen_list(tail, count);
2714114402Sru}
2715114402Sru
2716114402Sruint italic_corrected_node::character_type()
2717114402Sru{
2718114402Sru  return n->character_type();
2719114402Sru}
2720114402Sru
2721114402Sruclass break_char_node : public node {
2722114402Sru  node *ch;
2723114402Sru  char break_code;
2724114402Sru  color *col;
2725114402Srupublic:
2726114402Sru  break_char_node(node *, int, color *, node * = 0);
2727151497Sru  break_char_node(node *, int, color *, statem *, int, node * = 0);
2728114402Sru  ~break_char_node();
2729114402Sru  node *copy();
2730114402Sru  hunits width();
2731114402Sru  vunits vertical_width();
2732114402Sru  node *last_char_node();
2733114402Sru  int character_type();
2734114402Sru  int ends_sentence();
2735114402Sru  node *add_self(node *, hyphen_list **);
2736114402Sru  hyphen_list *get_hyphen_list(hyphen_list *, int *);
2737114402Sru  void tprint(troff_output_file *);
2738114402Sru  void zero_width_tprint(troff_output_file *);
2739114402Sru  void ascii_print(ascii_output_file *);
2740114402Sru  void asciify(macro *);
2741114402Sru  hyphenation_type get_hyphenation_type();
2742114402Sru  int overlaps_vertically();
2743114402Sru  int overlaps_horizontally();
2744114402Sru  units size();
2745114402Sru  tfont *get_tfont();
2746114402Sru  int same(node *);
2747114402Sru  const char *type();
2748114402Sru  int force_tprint();
2749151497Sru  int is_tag();
2750114402Sru};
2751114402Sru
2752114402Srubreak_char_node::break_char_node(node *n, int bc, color *c, node *x)
2753114402Sru: node(x), ch(n), break_code(bc), col(c)
2754114402Sru{
2755114402Sru}
2756114402Sru
2757151497Srubreak_char_node::break_char_node(node *n, int bc, color *c, statem *s,
2758151497Sru				 int pop, node *x)
2759151497Sru: node(x, s, pop), ch(n), break_code(bc), col(c)
2760151497Sru{
2761151497Sru}
2762151497Sru
2763114402Srubreak_char_node::~break_char_node()
2764114402Sru{
2765114402Sru  delete ch;
2766114402Sru}
2767114402Sru
2768114402Srunode *break_char_node::copy()
2769114402Sru{
2770151497Sru  return new break_char_node(ch->copy(), break_code, col, state,
2771151497Sru			     div_nest_level);
2772114402Sru}
2773114402Sru
2774114402Sruhunits break_char_node::width()
2775114402Sru{
2776114402Sru  return ch->width();
2777114402Sru}
2778114402Sru
2779114402Sruvunits break_char_node::vertical_width()
2780114402Sru{
2781114402Sru  return ch->vertical_width();
2782114402Sru}
2783114402Sru
2784114402Srunode *break_char_node::last_char_node()
2785114402Sru{
2786114402Sru  return ch->last_char_node();
2787114402Sru}
2788114402Sru
2789114402Sruint break_char_node::character_type()
2790114402Sru{
2791114402Sru  return ch->character_type();
2792114402Sru}
2793114402Sru
2794114402Sruint break_char_node::ends_sentence()
2795114402Sru{
2796114402Sru  return ch->ends_sentence();
2797114402Sru}
2798114402Sru
2799114402Srunode *break_char_node::add_self(node *n, hyphen_list **p)
2800114402Sru{
2801114402Sru  assert((*p)->hyphenation_code == 0);
2802114402Sru  if ((*p)->breakable && (break_code & 1)) {
2803114402Sru    n = new space_node(H0, col, n);
2804114402Sru    n->freeze_space();
2805114402Sru  }
2806114402Sru  next = n;
2807114402Sru  n = this;
2808114402Sru  if ((*p)->breakable && (break_code & 2)) {
2809114402Sru    n = new space_node(H0, col, n);
2810114402Sru    n->freeze_space();
2811114402Sru  }
2812114402Sru  hyphen_list *pp = *p;
2813114402Sru  *p = (*p)->next;
2814114402Sru  delete pp;
2815114402Sru  return n;
2816114402Sru}
2817114402Sru
2818114402Sruhyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail, int *)
2819114402Sru{
2820114402Sru  return new hyphen_list(0, tail);
2821114402Sru}
2822114402Sru
2823114402Sruhyphenation_type break_char_node::get_hyphenation_type()
2824114402Sru{
2825114402Sru  return HYPHEN_MIDDLE;
2826114402Sru}
2827114402Sru
2828114402Sruvoid break_char_node::ascii_print(ascii_output_file *ascii)
2829114402Sru{
2830114402Sru  ch->ascii_print(ascii);
2831114402Sru}
2832114402Sru
2833114402Sruint break_char_node::overlaps_vertically()
2834114402Sru{
2835114402Sru  return ch->overlaps_vertically();
2836114402Sru}
2837114402Sru
2838114402Sruint break_char_node::overlaps_horizontally()
2839114402Sru{
2840114402Sru  return ch->overlaps_horizontally();
2841114402Sru}
2842114402Sru
2843114402Sruunits break_char_node::size()
2844114402Sru{
2845114402Sru  return ch->size();
2846114402Sru}
2847114402Sru
2848114402Srutfont *break_char_node::get_tfont()
2849114402Sru{
2850114402Sru  return ch->get_tfont();
2851114402Sru}
2852114402Sru
2853114402Srunode *extra_size_node::copy()
2854114402Sru{
2855151497Sru  return new extra_size_node(n, state, div_nest_level);
2856114402Sru}
2857114402Sru
2858151497Sruextra_size_node::extra_size_node(vunits i, statem *s, int pop)
2859151497Sru: node(0, s, pop), n(i)
2860151497Sru{
2861151497Sru}
2862151497Sru
2863151497Sruextra_size_node::extra_size_node(vunits i)
2864151497Sru: n(i)
2865151497Sru{
2866151497Sru}
2867151497Sru
2868114402Srunode *vertical_size_node::copy()
2869114402Sru{
2870151497Sru  return new vertical_size_node(n, state, div_nest_level);
2871114402Sru}
2872114402Sru
2873151497Sruvertical_size_node::vertical_size_node(vunits i, statem *s, int pop)
2874151497Sru: node(0, s, pop), n(i)
2875151497Sru{
2876151497Sru}
2877151497Sru
2878151497Sruvertical_size_node::vertical_size_node(vunits i)
2879151497Sru: n(i)
2880151497Sru{
2881151497Sru}
2882151497Sru
2883114402Srunode *hmotion_node::copy()
2884114402Sru{
2885151497Sru  return new hmotion_node(n, was_tab, unformat, col, state, div_nest_level);
2886114402Sru}
2887114402Sru
2888114402Srunode *space_char_hmotion_node::copy()
2889114402Sru{
2890151497Sru  return new space_char_hmotion_node(n, col, state, div_nest_level);
2891114402Sru}
2892114402Sru
2893151497Sruvmotion_node::vmotion_node(vunits i, color *c)
2894151497Sru: n(i), col(c)
2895151497Sru{
2896151497Sru}
2897151497Sru
2898151497Sruvmotion_node::vmotion_node(vunits i, color *c, statem *s, int pop)
2899151497Sru: node(0, s, pop), n(i), col(c)
2900151497Sru{
2901151497Sru}
2902151497Sru
2903114402Srunode *vmotion_node::copy()
2904114402Sru{
2905151497Sru  return new vmotion_node(n, col, state, div_nest_level);
2906114402Sru}
2907114402Sru
2908114402Srunode *dummy_node::copy()
2909114402Sru{
2910114402Sru  return new dummy_node;
2911114402Sru}
2912114402Sru
2913114402Srunode *transparent_dummy_node::copy()
2914114402Sru{
2915114402Sru  return new transparent_dummy_node;
2916114402Sru}
2917114402Sru
2918114402Sruhline_node::~hline_node()
2919114402Sru{
2920114402Sru  if (n)
2921114402Sru    delete n;
2922114402Sru}
2923114402Sru
2924151497Sruhline_node::hline_node(hunits i, node *c, node *nxt)
2925151497Sru: node(nxt), x(i), n(c)
2926151497Sru{
2927151497Sru}
2928151497Sru
2929151497Sruhline_node::hline_node(hunits i, node *c, statem *s, int pop, node *nxt)
2930151497Sru: node(nxt, s, pop), x(i), n(c)
2931151497Sru{
2932151497Sru}
2933151497Sru
2934114402Srunode *hline_node::copy()
2935114402Sru{
2936151497Sru  return new hline_node(x, n ? n->copy() : 0, state, div_nest_level);
2937114402Sru}
2938114402Sru
2939114402Sruhunits hline_node::width()
2940114402Sru{
2941114402Sru  return x < H0 ? H0 : x;
2942114402Sru}
2943114402Sru
2944151497Sruvline_node::vline_node(vunits i, node *c, node *nxt)
2945151497Sru: node(nxt), x(i), n(c)
2946151497Sru{
2947151497Sru}
2948151497Sru
2949151497Sruvline_node::vline_node(vunits i, node *c, statem *s, int pop, node *nxt)
2950151497Sru: node(nxt, s, pop), x(i), n(c)
2951151497Sru{
2952151497Sru}
2953151497Sru
2954114402Sruvline_node::~vline_node()
2955114402Sru{
2956114402Sru  if (n)
2957114402Sru    delete n;
2958114402Sru}
2959114402Sru
2960114402Srunode *vline_node::copy()
2961114402Sru{
2962151497Sru  return new vline_node(x, n ? n->copy() : 0, state, div_nest_level);
2963114402Sru}
2964114402Sru
2965114402Sruhunits vline_node::width()
2966114402Sru{
2967114402Sru  return n == 0 ? H0 : n->width();
2968114402Sru}
2969114402Sru
2970151497Sruzero_width_node::zero_width_node(node *nd, statem *s, int pop)
2971151497Sru: node(0, s, pop), n(nd)
2972114402Sru{
2973114402Sru}
2974114402Sru
2975151497Sruzero_width_node::zero_width_node(node *nd)
2976151497Sru: n(nd)
2977151497Sru{
2978151497Sru}
2979151497Sru
2980114402Sruzero_width_node::~zero_width_node()
2981114402Sru{
2982114402Sru  delete_node_list(n);
2983114402Sru}
2984114402Sru
2985114402Srunode *zero_width_node::copy()
2986114402Sru{
2987151497Sru  return new zero_width_node(copy_node_list(n), state, div_nest_level);
2988114402Sru}
2989114402Sru
2990114402Sruint node_list_character_type(node *p)
2991114402Sru{
2992114402Sru  int t = 0;
2993114402Sru  for (; p; p = p->next)
2994114402Sru    t |= p->character_type();
2995114402Sru  return t;
2996114402Sru}
2997114402Sru
2998114402Sruint zero_width_node::character_type()
2999114402Sru{
3000114402Sru  return node_list_character_type(n);
3001114402Sru}
3002114402Sru
3003114402Sruvoid node_list_vertical_extent(node *p, vunits *min, vunits *max)
3004114402Sru{
3005114402Sru  *min = V0;
3006114402Sru  *max = V0;
3007114402Sru  vunits cur_vpos = V0;
3008114402Sru  vunits v1, v2;
3009114402Sru  for (; p; p = p->next) {
3010114402Sru    p->vertical_extent(&v1, &v2);
3011114402Sru    v1 += cur_vpos;
3012114402Sru    if (v1 < *min)
3013114402Sru      *min = v1;
3014114402Sru    v2 += cur_vpos;
3015114402Sru    if (v2 > *max)
3016114402Sru      *max = v2;
3017114402Sru    cur_vpos += p->vertical_width();
3018114402Sru  }
3019114402Sru}
3020114402Sru
3021114402Sruvoid zero_width_node::vertical_extent(vunits *min, vunits *max)
3022114402Sru{
3023114402Sru  node_list_vertical_extent(n, min, max);
3024114402Sru}
3025114402Sru
3026151497Sruoverstrike_node::overstrike_node()
3027151497Sru: list(0), max_width(H0)
3028114402Sru{
3029114402Sru}
3030114402Sru
3031151497Sruoverstrike_node::overstrike_node(statem *s, int pop)
3032151497Sru: node(0, s, pop), list(0), max_width(H0)
3033151497Sru{
3034151497Sru}
3035151497Sru
3036114402Sruoverstrike_node::~overstrike_node()
3037114402Sru{
3038114402Sru  delete_node_list(list);
3039114402Sru}
3040114402Sru
3041114402Srunode *overstrike_node::copy()
3042114402Sru{
3043151497Sru  overstrike_node *on = new overstrike_node(state, div_nest_level);
3044114402Sru  for (node *tem = list; tem; tem = tem->next)
3045114402Sru    on->overstrike(tem->copy());
3046114402Sru  return on;
3047114402Sru}
3048114402Sru
3049114402Sruvoid overstrike_node::overstrike(node *n)
3050114402Sru{
3051114402Sru  if (n == 0)
3052114402Sru    return;
3053114402Sru  hunits w = n->width();
3054114402Sru  if (w > max_width)
3055114402Sru    max_width = w;
3056114402Sru  node **p;
3057114402Sru  for (p = &list; *p; p = &(*p)->next)
3058114402Sru    ;
3059114402Sru  n->next = 0;
3060114402Sru  *p = n;
3061114402Sru}
3062114402Sru
3063114402Sruhunits overstrike_node::width()
3064114402Sru{
3065114402Sru  return max_width;
3066114402Sru}
3067114402Sru
3068151497Srubracket_node::bracket_node()
3069151497Sru: list(0), max_width(H0)
3070114402Sru{
3071114402Sru}
3072114402Sru
3073151497Srubracket_node::bracket_node(statem *s, int pop)
3074151497Sru: node(0, s, pop), list(0), max_width(H0)
3075151497Sru{
3076151497Sru}
3077151497Sru
3078114402Srubracket_node::~bracket_node()
3079114402Sru{
3080114402Sru  delete_node_list(list);
3081114402Sru}
3082114402Sru
3083114402Srunode *bracket_node::copy()
3084114402Sru{
3085151497Sru  bracket_node *on = new bracket_node(state, div_nest_level);
3086151497Sru  node *last_node = 0;
3087114402Sru  node *tem;
3088114402Sru  if (list)
3089114402Sru    list->last = 0;
3090114402Sru  for (tem = list; tem; tem = tem->next) {
3091114402Sru    if (tem->next)
3092114402Sru      tem->next->last = tem;
3093151497Sru    last_node = tem;
3094114402Sru  }
3095151497Sru  for (tem = last_node; tem; tem = tem->last)
3096114402Sru    on->bracket(tem->copy());
3097114402Sru  return on;
3098114402Sru}
3099114402Sru
3100114402Sruvoid bracket_node::bracket(node *n)
3101114402Sru{
3102114402Sru  if (n == 0)
3103114402Sru    return;
3104114402Sru  hunits w = n->width();
3105114402Sru  if (w > max_width)
3106114402Sru    max_width = w;
3107114402Sru  n->next = list;
3108114402Sru  list = n;
3109114402Sru}
3110114402Sru
3111114402Sruhunits bracket_node::width()
3112114402Sru{
3113114402Sru  return max_width;
3114114402Sru}
3115114402Sru
3116114402Sruint node::nspaces()
3117114402Sru{
3118114402Sru  return 0;
3119114402Sru}
3120114402Sru
3121114402Sruint node::merge_space(hunits, hunits, hunits)
3122114402Sru{
3123114402Sru  return 0;
3124114402Sru}
3125114402Sru
3126114402Sru#if 0
3127114402Sruspace_node *space_node::free_list = 0;
3128114402Sru
3129114402Sruvoid *space_node::operator new(size_t n)
3130114402Sru{
3131114402Sru  assert(n == sizeof(space_node));
3132114402Sru  if (!free_list) {
3133114402Sru    free_list = (space_node *)new char[sizeof(space_node)*BLOCK];
3134114402Sru    for (int i = 0; i < BLOCK - 1; i++)
3135114402Sru      free_list[i].next = free_list + i + 1;
3136114402Sru    free_list[BLOCK-1].next = 0;
3137114402Sru  }
3138114402Sru  space_node *p = free_list;
3139114402Sru  free_list = (space_node *)(free_list->next);
3140114402Sru  p->next = 0;
3141114402Sru  return p;
3142114402Sru}
3143114402Sru
3144114402Sruinline void space_node::operator delete(void *p)
3145114402Sru{
3146114402Sru  if (p) {
3147114402Sru    ((space_node *)p)->next = free_list;
3148114402Sru    free_list = (space_node *)p;
3149114402Sru  }
3150114402Sru}
3151114402Sru#endif
3152114402Sru
3153114402Sruspace_node::space_node(hunits nn, color *c, node *p)
3154151497Sru: node(p, 0, 0), n(nn), set(0), was_escape_colon(0), col(c)
3155114402Sru{
3156114402Sru}
3157114402Sru
3158151497Sruspace_node::space_node(hunits nn, color *c, statem *s, int pop, node *p)
3159151497Sru: node(p, s, pop), n(nn), set(0), was_escape_colon(0), col(c)
3160114402Sru{
3161114402Sru}
3162114402Sru
3163151497Sruspace_node::space_node(hunits nn, int s, int flag, color *c, statem *st,
3164151497Sru		       int pop, node *p)
3165151497Sru: node(p, st, pop), n(nn), set(s), was_escape_colon(flag), col(c)
3166151497Sru{
3167151497Sru}
3168151497Sru
3169114402Sru#if 0
3170114402Sruspace_node::~space_node()
3171114402Sru{
3172114402Sru}
3173114402Sru#endif
3174114402Sru
3175114402Srunode *space_node::copy()
3176114402Sru{
3177151497Sru  return new space_node(n, set, was_escape_colon, col, state, div_nest_level);
3178114402Sru}
3179114402Sru
3180114402Sruint space_node::force_tprint()
3181114402Sru{
3182114402Sru  return 0;
3183114402Sru}
3184114402Sru
3185151497Sruint space_node::is_tag()
3186151497Sru{
3187151497Sru  return 0;
3188151497Sru}
3189151497Sru
3190114402Sruint space_node::nspaces()
3191114402Sru{
3192114402Sru  return set ? 0 : 1;
3193114402Sru}
3194114402Sru
3195114402Sruint space_node::merge_space(hunits h, hunits, hunits)
3196114402Sru{
3197114402Sru  n += h;
3198114402Sru  return 1;
3199114402Sru}
3200114402Sru
3201114402Sruhunits space_node::width()
3202114402Sru{
3203114402Sru  return n;
3204114402Sru}
3205114402Sru
3206114402Sruvoid node::spread_space(int*, hunits*)
3207114402Sru{
3208114402Sru}
3209114402Sru
3210151497Sruvoid space_node::spread_space(int *n_spaces, hunits *desired_space)
3211114402Sru{
3212114402Sru  if (!set) {
3213151497Sru    assert(*n_spaces > 0);
3214151497Sru    if (*n_spaces == 1) {
3215114402Sru      n += *desired_space;
3216114402Sru      *desired_space = H0;
3217114402Sru    }
3218114402Sru    else {
3219151497Sru      hunits extra = *desired_space / *n_spaces;
3220114402Sru      *desired_space -= extra;
3221114402Sru      n += extra;
3222114402Sru    }
3223151497Sru    *n_spaces -= 1;
3224114402Sru    set = 1;
3225114402Sru  }
3226114402Sru}
3227114402Sru
3228114402Sruvoid node::freeze_space()
3229114402Sru{
3230114402Sru}
3231114402Sru
3232114402Sruvoid space_node::freeze_space()
3233114402Sru{
3234114402Sru  set = 1;
3235114402Sru}
3236114402Sru
3237114402Sruvoid node::is_escape_colon()
3238114402Sru{
3239114402Sru}
3240114402Sru
3241114402Sruvoid space_node::is_escape_colon()
3242114402Sru{
3243114402Sru  was_escape_colon = 1;
3244114402Sru}
3245114402Sru
3246151497Srudiverted_space_node::diverted_space_node(vunits d, statem *s, int pop,
3247151497Sru					 node *p)
3248151497Sru: node(p, s, pop), n(d)
3249151497Sru{
3250151497Sru}
3251151497Sru
3252114402Srudiverted_space_node::diverted_space_node(vunits d, node *p)
3253114402Sru: node(p), n(d)
3254114402Sru{
3255114402Sru}
3256114402Sru
3257114402Srunode *diverted_space_node::copy()
3258114402Sru{
3259151497Sru  return new diverted_space_node(n, state, div_nest_level);
3260114402Sru}
3261114402Sru
3262151497Srudiverted_copy_file_node::diverted_copy_file_node(symbol s, statem *st,
3263151497Sru						 int pop, node *p)
3264151497Sru: node(p, st, pop), filename(s)
3265151497Sru{
3266151497Sru}
3267151497Sru
3268114402Srudiverted_copy_file_node::diverted_copy_file_node(symbol s, node *p)
3269114402Sru: node(p), filename(s)
3270114402Sru{
3271114402Sru}
3272114402Sru
3273114402Srunode *diverted_copy_file_node::copy()
3274114402Sru{
3275151497Sru  return new diverted_copy_file_node(filename, state, div_nest_level);
3276114402Sru}
3277114402Sru
3278114402Sruint node::ends_sentence()
3279114402Sru{
3280114402Sru  return 0;
3281114402Sru}
3282114402Sru
3283114402Sruint kern_pair_node::ends_sentence()
3284114402Sru{
3285114402Sru  switch (n2->ends_sentence()) {
3286114402Sru  case 0:
3287114402Sru    return 0;
3288114402Sru  case 1:
3289114402Sru    return 1;
3290114402Sru  case 2:
3291114402Sru    break;
3292114402Sru  default:
3293114402Sru    assert(0);
3294114402Sru  }
3295114402Sru  return n1->ends_sentence();
3296114402Sru}
3297114402Sru
3298114402Sruint node_list_ends_sentence(node *n)
3299114402Sru{
3300114402Sru  for (; n != 0; n = n->next)
3301114402Sru    switch (n->ends_sentence()) {
3302114402Sru    case 0:
3303114402Sru      return 0;
3304114402Sru    case 1:
3305114402Sru      return 1;
3306114402Sru    case 2:
3307114402Sru      break;
3308114402Sru    default:
3309114402Sru      assert(0);
3310114402Sru    }
3311114402Sru  return 2;
3312114402Sru}
3313114402Sru
3314114402Sruint dbreak_node::ends_sentence()
3315114402Sru{
3316114402Sru  return node_list_ends_sentence(none);
3317114402Sru}
3318114402Sru
3319114402Sruint node::overlaps_horizontally()
3320114402Sru{
3321114402Sru  return 0;
3322114402Sru}
3323114402Sru
3324114402Sruint node::overlaps_vertically()
3325114402Sru{
3326114402Sru  return 0;
3327114402Sru}
3328114402Sru
3329114402Sruint node::discardable()
3330114402Sru{
3331114402Sru  return 0;
3332114402Sru}
3333114402Sru
3334114402Sruint space_node::discardable()
3335114402Sru{
3336114402Sru  return set ? 0 : 1;
3337114402Sru}
3338114402Sru
3339114402Sruvunits node::vertical_width()
3340114402Sru{
3341114402Sru  return V0;
3342114402Sru}
3343114402Sru
3344114402Sruvunits vline_node::vertical_width()
3345114402Sru{
3346114402Sru  return x;
3347114402Sru}
3348114402Sru
3349114402Sruvunits vmotion_node::vertical_width()
3350114402Sru{
3351114402Sru  return n;
3352114402Sru}
3353114402Sru
3354114402Sruint node::set_unformat_flag()
3355114402Sru{
3356114402Sru  return 1;
3357114402Sru}
3358114402Sru
3359114402Sruint node::character_type()
3360114402Sru{
3361114402Sru  return 0;
3362114402Sru}
3363114402Sru
3364114402Sruhunits node::subscript_correction()
3365114402Sru{
3366114402Sru  return H0;
3367114402Sru}
3368114402Sru
3369114402Sruhunits node::italic_correction()
3370114402Sru{
3371114402Sru  return H0;
3372114402Sru}
3373114402Sru
3374114402Sruhunits node::left_italic_correction()
3375114402Sru{
3376114402Sru  return H0;
3377114402Sru}
3378114402Sru
3379114402Sruhunits node::skew()
3380114402Sru{
3381114402Sru  return H0;
3382114402Sru}
3383114402Sru
3384114402Sru/* vertical_extent methods */
3385114402Sru
3386114402Sruvoid node::vertical_extent(vunits *min, vunits *max)
3387114402Sru{
3388114402Sru  vunits v = vertical_width();
3389114402Sru  if (v < V0) {
3390114402Sru    *min = v;
3391114402Sru    *max = V0;
3392114402Sru  }
3393114402Sru  else {
3394114402Sru    *max = v;
3395114402Sru    *min = V0;
3396114402Sru  }
3397114402Sru}
3398114402Sru
3399114402Sruvoid vline_node::vertical_extent(vunits *min, vunits *max)
3400114402Sru{
3401114402Sru  if (n == 0)
3402114402Sru    node::vertical_extent(min, max);
3403114402Sru  else {
3404114402Sru    vunits cmin, cmax;
3405114402Sru    n->vertical_extent(&cmin, &cmax);
3406114402Sru    vunits h = n->size();
3407114402Sru    if (x < V0) {
3408114402Sru      if (-x < h) {
3409114402Sru	*min = x;
3410114402Sru	*max = V0;
3411114402Sru      }
3412114402Sru      else {
3413114402Sru	// we print the first character and then move up, so
3414114402Sru	*max = cmax;
3415114402Sru	// we print the last character and then move up h
3416114402Sru	*min = cmin + h;
3417114402Sru	if (*min > V0)
3418114402Sru	  *min = V0;
3419114402Sru	*min += x;
3420114402Sru      }
3421114402Sru    }
3422114402Sru    else {
3423114402Sru      if (x < h) {
3424114402Sru	*max = x;
3425114402Sru	*min = V0;
3426114402Sru      }
3427114402Sru      else {
3428114402Sru	// we move down by h and then print the first character, so
3429114402Sru	*min = cmin + h;
3430114402Sru	if (*min > V0)
3431114402Sru	  *min = V0;
3432114402Sru	*max = x + cmax;
3433114402Sru      }
3434114402Sru    }
3435114402Sru  }
3436114402Sru}
3437114402Sru
3438114402Sru/* ascii_print methods */
3439114402Sru
3440114402Srustatic void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n)
3441114402Sru{
3442114402Sru  if (n == 0)
3443114402Sru    return;
3444114402Sru  ascii_print_reverse_node_list(ascii, n->next);
3445114402Sru  n->ascii_print(ascii);
3446114402Sru}
3447114402Sru
3448114402Sruvoid dbreak_node::ascii_print(ascii_output_file *ascii)
3449114402Sru{
3450114402Sru  ascii_print_reverse_node_list(ascii, none);
3451114402Sru}
3452114402Sru
3453114402Sruvoid kern_pair_node::ascii_print(ascii_output_file *ascii)
3454114402Sru{
3455114402Sru  n1->ascii_print(ascii);
3456114402Sru  n2->ascii_print(ascii);
3457114402Sru}
3458114402Sru
3459114402Sruvoid node::ascii_print(ascii_output_file *)
3460114402Sru{
3461114402Sru}
3462114402Sru
3463114402Sruvoid space_node::ascii_print(ascii_output_file *ascii)
3464114402Sru{
3465114402Sru  if (!n.is_zero())
3466114402Sru    ascii->outc(' ');
3467114402Sru}
3468114402Sru
3469114402Sruvoid hmotion_node::ascii_print(ascii_output_file *ascii)
3470114402Sru{
3471114402Sru  // this is pretty arbitrary
3472114402Sru  if (n >= points_to_units(2))
3473114402Sru    ascii->outc(' ');
3474114402Sru}
3475114402Sru
3476114402Sruvoid space_char_hmotion_node::ascii_print(ascii_output_file *ascii)
3477114402Sru{
3478114402Sru  ascii->outc(' ');
3479114402Sru}
3480114402Sru
3481114402Sru/* asciify methods */
3482114402Sru
3483114402Sruvoid node::asciify(macro *m)
3484114402Sru{
3485114402Sru  m->append(this);
3486114402Sru}
3487114402Sru
3488114402Sruvoid glyph_node::asciify(macro *m)
3489114402Sru{
3490114402Sru  unsigned char c = ci->get_asciify_code();
3491114402Sru  if (c == 0)
3492114402Sru    c = ci->get_ascii_code();
3493114402Sru  if (c != 0) {
3494114402Sru    m->append(c);
3495114402Sru    delete this;
3496114402Sru  }
3497114402Sru  else
3498114402Sru    m->append(this);
3499114402Sru}
3500114402Sru
3501114402Sruvoid kern_pair_node::asciify(macro *m)
3502114402Sru{
3503114402Sru  n1->asciify(m);
3504114402Sru  n2->asciify(m);
3505114402Sru  n1 = n2 = 0;
3506114402Sru  delete this;
3507114402Sru}
3508114402Sru
3509114402Srustatic void asciify_reverse_node_list(macro *m, node *n)
3510114402Sru{
3511114402Sru  if (n == 0)
3512114402Sru    return;
3513114402Sru  asciify_reverse_node_list(m, n->next);
3514114402Sru  n->asciify(m);
3515114402Sru}
3516114402Sru
3517114402Sruvoid dbreak_node::asciify(macro *m)
3518114402Sru{
3519114402Sru  asciify_reverse_node_list(m, none);
3520114402Sru  none = 0;
3521114402Sru  delete this;
3522114402Sru}
3523114402Sru
3524114402Sruvoid ligature_node::asciify(macro *m)
3525114402Sru{
3526114402Sru  n1->asciify(m);
3527114402Sru  n2->asciify(m);
3528114402Sru  n1 = n2 = 0;
3529114402Sru  delete this;
3530114402Sru}
3531114402Sru
3532114402Sruvoid break_char_node::asciify(macro *m)
3533114402Sru{
3534114402Sru  ch->asciify(m);
3535114402Sru  ch = 0;
3536114402Sru  delete this;
3537114402Sru}
3538114402Sru
3539114402Sruvoid italic_corrected_node::asciify(macro *m)
3540114402Sru{
3541114402Sru  n->asciify(m);
3542114402Sru  n = 0;
3543114402Sru  delete this;
3544114402Sru}
3545114402Sru
3546114402Sruvoid left_italic_corrected_node::asciify(macro *m)
3547114402Sru{
3548114402Sru  if (n) {
3549114402Sru    n->asciify(m);
3550114402Sru    n = 0;
3551114402Sru  }
3552114402Sru  delete this;
3553114402Sru}
3554114402Sru
3555114402Sruvoid hmotion_node::asciify(macro *m)
3556114402Sru{
3557114402Sru  if (was_tab) {
3558114402Sru    m->append('\t');
3559114402Sru    delete this;
3560114402Sru  }
3561114402Sru  else
3562114402Sru    m->append(this);
3563114402Sru}
3564114402Sru
3565114402Sruspace_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3566151497Sru						 statem *s, int pop,
3567151497Sru						 node *nxt)
3568151497Sru: hmotion_node(i, c, s, pop, nxt)
3569114402Sru{
3570114402Sru}
3571114402Sru
3572151497Sruspace_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3573151497Sru 						 node *nxt)
3574151497Sru: hmotion_node(i, c, 0, 0, nxt)
3575151497Sru{
3576151497Sru}
3577151497Sru
3578114402Sruvoid space_char_hmotion_node::asciify(macro *m)
3579114402Sru{
3580114402Sru  m->append(ESCAPE_SPACE);
3581114402Sru  delete this;
3582114402Sru}
3583114402Sru
3584114402Sruvoid space_node::asciify(macro *m)
3585114402Sru{
3586114402Sru  if (was_escape_colon) {
3587114402Sru    m->append(ESCAPE_COLON);
3588114402Sru    delete this;
3589114402Sru  }
3590114402Sru  else
3591114402Sru    m->append(this);
3592114402Sru}
3593114402Sru
3594114402Sruvoid word_space_node::asciify(macro *m)
3595114402Sru{
3596114402Sru  for (width_list *w = orig_width; w; w = w->next)
3597114402Sru    m->append(' ');
3598114402Sru  delete this;
3599114402Sru}
3600114402Sru
3601114402Sruvoid unbreakable_space_node::asciify(macro *m)
3602114402Sru{
3603114402Sru  m->append(ESCAPE_TILDE);
3604114402Sru  delete this;
3605114402Sru}
3606114402Sru
3607114402Sruvoid line_start_node::asciify(macro *)
3608114402Sru{
3609114402Sru  delete this;
3610114402Sru}
3611114402Sru
3612114402Sruvoid vertical_size_node::asciify(macro *)
3613114402Sru{
3614114402Sru  delete this;
3615114402Sru}
3616114402Sru
3617114402Srubreakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/,
3618114402Sru				  breakpoint *rest, int /*is_inner*/)
3619114402Sru{
3620114402Sru  return rest;
3621114402Sru}
3622114402Sru
3623114402Sruint node::nbreaks()
3624114402Sru{
3625114402Sru  return 0;
3626114402Sru}
3627114402Sru
3628151497Srubreakpoint *space_node::get_breakpoints(hunits wd, int ns,
3629114402Sru					breakpoint *rest, int is_inner)
3630114402Sru{
3631151497Sru  if (next && next->discardable())
3632114402Sru    return rest;
3633114402Sru  breakpoint *bp = new breakpoint;
3634114402Sru  bp->next = rest;
3635151497Sru  bp->width = wd;
3636114402Sru  bp->nspaces = ns;
3637114402Sru  bp->hyphenated = 0;
3638114402Sru  if (is_inner) {
3639114402Sru    assert(rest != 0);
3640114402Sru    bp->index = rest->index + 1;
3641114402Sru    bp->nd = rest->nd;
3642114402Sru  }
3643114402Sru  else {
3644114402Sru    bp->nd = this;
3645114402Sru    bp->index = 0;
3646114402Sru  }
3647114402Sru  return bp;
3648114402Sru}
3649114402Sru
3650114402Sruint space_node::nbreaks()
3651114402Sru{
3652151497Sru  if (next && next->discardable())
3653114402Sru    return 0;
3654114402Sru  else
3655114402Sru    return 1;
3656114402Sru}
3657114402Sru
3658114402Srustatic breakpoint *node_list_get_breakpoints(node *p, hunits *widthp,
3659114402Sru					     int ns, breakpoint *rest)
3660114402Sru{
3661114402Sru  if (p != 0) {
3662114402Sru    rest = p->get_breakpoints(*widthp,
3663114402Sru			      ns,
3664114402Sru			      node_list_get_breakpoints(p->next, widthp, ns,
3665114402Sru							rest),
3666114402Sru			      1);
3667114402Sru    *widthp += p->width();
3668114402Sru  }
3669114402Sru  return rest;
3670114402Sru}
3671114402Sru
3672151497Srubreakpoint *dbreak_node::get_breakpoints(hunits wd, int ns,
3673114402Sru					 breakpoint *rest, int is_inner)
3674114402Sru{
3675114402Sru  breakpoint *bp = new breakpoint;
3676114402Sru  bp->next = rest;
3677151497Sru  bp->width = wd;
3678114402Sru  for (node *tem = pre; tem != 0; tem = tem->next)
3679114402Sru    bp->width += tem->width();
3680114402Sru  bp->nspaces = ns;
3681114402Sru  bp->hyphenated = 1;
3682114402Sru  if (is_inner) {
3683114402Sru    assert(rest != 0);
3684114402Sru    bp->index = rest->index + 1;
3685114402Sru    bp->nd = rest->nd;
3686114402Sru  }
3687114402Sru  else {
3688114402Sru    bp->nd = this;
3689114402Sru    bp->index = 0;
3690114402Sru  }
3691151497Sru  return node_list_get_breakpoints(none, &wd, ns, bp);
3692114402Sru}
3693114402Sru
3694114402Sruint dbreak_node::nbreaks()
3695114402Sru{
3696114402Sru  int i = 1;
3697114402Sru  for (node *tem = none; tem != 0; tem = tem->next)
3698114402Sru    i += tem->nbreaks();
3699114402Sru  return i;
3700114402Sru}
3701114402Sru
3702114402Sruvoid node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/)
3703114402Sru{
3704114402Sru  assert(0);
3705114402Sru}
3706114402Sru
3707114402Sruvoid space_node::split(int where, node **pre, node **post)
3708114402Sru{
3709114402Sru  assert(where == 0);
3710114402Sru  *pre = next;
3711114402Sru  *post = 0;
3712114402Sru  delete this;
3713114402Sru}
3714114402Sru
3715114402Srustatic void node_list_split(node *p, int *wherep, node **prep, node **postp)
3716114402Sru{
3717114402Sru  if (p == 0)
3718114402Sru    return;
3719114402Sru  int nb = p->nbreaks();
3720114402Sru  node_list_split(p->next, wherep, prep, postp);
3721114402Sru  if (*wherep < 0) {
3722114402Sru    p->next = *postp;
3723114402Sru    *postp = p;
3724114402Sru  }
3725114402Sru  else if (*wherep < nb) {
3726114402Sru    p->next = *prep;
3727114402Sru    p->split(*wherep, prep, postp);
3728114402Sru  }
3729114402Sru  else {
3730114402Sru    p->next = *prep;
3731114402Sru    *prep = p;
3732114402Sru  }
3733114402Sru  *wherep -= nb;
3734114402Sru}
3735114402Sru
3736114402Sruvoid dbreak_node::split(int where, node **prep, node **postp)
3737114402Sru{
3738114402Sru  assert(where >= 0);
3739114402Sru  if (where == 0) {
3740114402Sru    *postp = post;
3741114402Sru    post = 0;
3742114402Sru    if (pre == 0)
3743114402Sru      *prep = next;
3744114402Sru    else {
3745114402Sru      node *tem;
3746114402Sru      for (tem = pre; tem->next != 0; tem = tem->next)
3747114402Sru	;
3748114402Sru      tem->next = next;
3749114402Sru      *prep = pre;
3750114402Sru    }
3751114402Sru    pre = 0;
3752114402Sru    delete this;
3753114402Sru  }
3754114402Sru  else {
3755114402Sru    *prep = next;
3756114402Sru    where -= 1;
3757114402Sru    node_list_split(none, &where, prep, postp);
3758114402Sru    none = 0;
3759114402Sru    delete this;
3760114402Sru  }
3761114402Sru}
3762114402Sru
3763114402Sruhyphenation_type node::get_hyphenation_type()
3764114402Sru{
3765114402Sru  return HYPHEN_BOUNDARY;
3766114402Sru}
3767114402Sru
3768114402Sruhyphenation_type dbreak_node::get_hyphenation_type()
3769114402Sru{
3770114402Sru  return HYPHEN_INHIBIT;
3771114402Sru}
3772114402Sru
3773114402Sruhyphenation_type kern_pair_node::get_hyphenation_type()
3774114402Sru{
3775114402Sru  return HYPHEN_MIDDLE;
3776114402Sru}
3777114402Sru
3778114402Sruhyphenation_type dummy_node::get_hyphenation_type()
3779114402Sru{
3780114402Sru  return HYPHEN_MIDDLE;
3781114402Sru}
3782114402Sru
3783114402Sruhyphenation_type transparent_dummy_node::get_hyphenation_type()
3784114402Sru{
3785114402Sru  return HYPHEN_MIDDLE;
3786114402Sru}
3787114402Sru
3788114402Sruhyphenation_type hmotion_node::get_hyphenation_type()
3789114402Sru{
3790114402Sru  return HYPHEN_MIDDLE;
3791114402Sru}
3792114402Sru
3793114402Sruhyphenation_type space_char_hmotion_node::get_hyphenation_type()
3794114402Sru{
3795114402Sru  return HYPHEN_MIDDLE;
3796114402Sru}
3797114402Sru
3798114402Sruhyphenation_type overstrike_node::get_hyphenation_type()
3799114402Sru{
3800114402Sru  return HYPHEN_MIDDLE;
3801114402Sru}
3802114402Sru
3803114402Sruhyphenation_type space_node::get_hyphenation_type()
3804114402Sru{
3805114402Sru  if (was_escape_colon)
3806114402Sru    return HYPHEN_MIDDLE;
3807114402Sru  return HYPHEN_BOUNDARY;
3808114402Sru}
3809114402Sru
3810114402Sruhyphenation_type unbreakable_space_node::get_hyphenation_type()
3811114402Sru{
3812114402Sru  return HYPHEN_MIDDLE;
3813114402Sru}
3814114402Sru
3815114402Sruint node::interpret(macro *)
3816114402Sru{
3817114402Sru  return 0;
3818114402Sru}
3819114402Sru
3820114402Sruspecial_node::special_node(const macro &m, int n)
3821114402Sru: mac(m), no_init_string(n)
3822114402Sru{
3823114402Sru  font_size fs = curenv->get_font_size();
3824114402Sru  int char_height = curenv->get_char_height();
3825114402Sru  int char_slant = curenv->get_char_slant();
3826114402Sru  int fontno = env_definite_font(curenv);
3827114402Sru  tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno);
3828114402Sru  if (curenv->is_composite())
3829114402Sru    tf = tf->get_plain();
3830114402Sru  gcol = curenv->get_glyph_color();
3831114402Sru  fcol = curenv->get_fill_color();
3832151497Sru  is_special = 1;
3833114402Sru}
3834114402Sru
3835114402Sruspecial_node::special_node(const macro &m, tfont *t,
3836151497Sru			   color *gc, color *fc,
3837151497Sru			   statem *s, int pop,
3838151497Sru			   int n)
3839151497Sru: node(0, s, pop), mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n)
3840114402Sru{
3841151497Sru  is_special = 1;
3842114402Sru}
3843114402Sru
3844114402Sruint special_node::same(node *n)
3845114402Sru{
3846114402Sru  return mac == ((special_node *)n)->mac
3847114402Sru	 && tf == ((special_node *)n)->tf
3848114402Sru	 && gcol == ((special_node *)n)->gcol
3849114402Sru	 && fcol == ((special_node *)n)->fcol
3850114402Sru	 && no_init_string == ((special_node *)n)->no_init_string;
3851114402Sru}
3852114402Sru
3853114402Sruconst char *special_node::type()
3854114402Sru{
3855114402Sru  return "special_node";
3856114402Sru}
3857114402Sru
3858114402Sruint special_node::ends_sentence()
3859114402Sru{
3860114402Sru  return 2;
3861114402Sru}
3862114402Sru
3863114402Sruint special_node::force_tprint()
3864114402Sru{
3865114402Sru  return 0;
3866114402Sru}
3867114402Sru
3868151497Sruint special_node::is_tag()
3869151497Sru{
3870151497Sru  return 0;
3871151497Sru}
3872151497Sru
3873114402Srunode *special_node::copy()
3874114402Sru{
3875151497Sru  return new special_node(mac, tf, gcol, fcol, state, div_nest_level,
3876151497Sru			  no_init_string);
3877114402Sru}
3878114402Sru
3879114402Sruvoid special_node::tprint_start(troff_output_file *out)
3880114402Sru{
3881114402Sru  out->start_special(tf, gcol, fcol, no_init_string);
3882114402Sru}
3883114402Sru
3884114402Sruvoid special_node::tprint_char(troff_output_file *out, unsigned char c)
3885114402Sru{
3886114402Sru  out->special_char(c);
3887114402Sru}
3888114402Sru
3889114402Sruvoid special_node::tprint_end(troff_output_file *out)
3890114402Sru{
3891114402Sru  out->end_special();
3892114402Sru}
3893114402Sru
3894114402Srutfont *special_node::get_tfont()
3895114402Sru{
3896114402Sru  return tf;
3897114402Sru}
3898114402Sru
3899114402Sru/* suppress_node */
3900114402Sru
3901114402Srusuppress_node::suppress_node(int on_or_off, int issue_limits)
3902151497Sru: is_on(on_or_off), emit_limits(issue_limits), filename(0), position(0),
3903151497Sru  image_id(0)
3904114402Sru{
3905114402Sru}
3906114402Sru
3907114402Srusuppress_node::suppress_node(symbol f, char p, int id)
3908114402Sru: is_on(2), emit_limits(0), filename(f), position(p), image_id(id)
3909114402Sru{
3910151497Sru  is_special = 1;
3911114402Sru}
3912114402Sru
3913114402Srusuppress_node::suppress_node(int issue_limits, int on_or_off,
3914151497Sru			     symbol f, char p, int id,
3915151497Sru			     statem *s, int pop)
3916151497Sru: node(0, s, pop), is_on(on_or_off), emit_limits(issue_limits), filename(f),
3917151497Sru  position(p), image_id(id)
3918114402Sru{
3919114402Sru}
3920114402Sru
3921114402Sruint suppress_node::same(node *n)
3922114402Sru{
3923114402Sru  return ((is_on == ((suppress_node *)n)->is_on)
3924114402Sru	  && (emit_limits == ((suppress_node *)n)->emit_limits)
3925114402Sru	  && (filename == ((suppress_node *)n)->filename)
3926114402Sru	  && (position == ((suppress_node *)n)->position)
3927114402Sru	  && (image_id == ((suppress_node *)n)->image_id));
3928114402Sru}
3929114402Sru
3930114402Sruconst char *suppress_node::type()
3931114402Sru{
3932114402Sru  return "suppress_node";
3933114402Sru}
3934114402Sru
3935114402Srunode *suppress_node::copy()
3936114402Sru{
3937151497Sru  return new suppress_node(emit_limits, is_on, filename, position, image_id,
3938151497Sru			   state, div_nest_level);
3939114402Sru}
3940114402Sru
3941151497Sru/* tag_node */
3942151497Sru
3943151497Srutag_node::tag_node()
3944151497Sru: delayed(0)
3945151497Sru{
3946151497Sru  is_special = 1;
3947151497Sru}
3948151497Sru
3949151497Srutag_node::tag_node(string s, int delay)
3950151497Sru: tag_string(s), delayed(delay)
3951151497Sru{
3952151497Sru  is_special = !delay;
3953151497Sru}
3954151497Sru
3955151497Srutag_node::tag_node(string s, statem *st, int pop, int delay)
3956151497Sru: node(0, st, pop), tag_string(s), delayed(delay)
3957151497Sru{
3958151497Sru  is_special = !delay;
3959151497Sru}
3960151497Sru
3961151497Srunode *tag_node::copy()
3962151497Sru{
3963151497Sru  return new tag_node(tag_string, state, div_nest_level, delayed);
3964151497Sru}
3965151497Sru
3966151497Sruvoid tag_node::tprint(troff_output_file *out)
3967151497Sru{
3968151497Sru  if (delayed)
3969151497Sru    out->add_to_tag_list(tag_string);
3970151497Sru  else
3971151497Sru    out->state.add_tag(out->fp, tag_string);
3972151497Sru}
3973151497Sru
3974151497Sruint tag_node::same(node *nd)
3975151497Sru{
3976151497Sru  return tag_string == ((tag_node *)nd)->tag_string
3977151497Sru	 && delayed == ((tag_node *)nd)->delayed;
3978151497Sru}
3979151497Sru
3980151497Sruconst char *tag_node::type()
3981151497Sru{
3982151497Sru  return "tag_node";
3983151497Sru}
3984151497Sru
3985151497Sruint tag_node::force_tprint()
3986151497Sru{
3987151497Sru  return !delayed;
3988151497Sru}
3989151497Sru
3990151497Sruint tag_node::is_tag()
3991151497Sru{
3992151497Sru  return !delayed;
3993151497Sru}
3994151497Sru
3995151497Sruint tag_node::ends_sentence()
3996151497Sru{
3997151497Sru  return 2;
3998151497Sru}
3999151497Sru
4000114402Sruint get_reg_int(const char *p)
4001114402Sru{
4002114402Sru  reg *r = (reg *)number_reg_dictionary.lookup(p);
4003114402Sru  units prev_value;
4004114402Sru  if (r && (r->get_value(&prev_value)))
4005114402Sru    return (int)prev_value;
4006114402Sru  else
4007114402Sru    warning(WARN_REG, "number register `%1' not defined", p);
4008114402Sru  return 0;
4009114402Sru}
4010114402Sru
4011114402Sruconst char *get_reg_str(const char *p)
4012114402Sru{
4013114402Sru  reg *r = (reg *)number_reg_dictionary.lookup(p);
4014114402Sru  if (r)
4015114402Sru    return r->get_string();
4016114402Sru  else
4017114402Sru    warning(WARN_REG, "register `%1' not defined", p);
4018114402Sru  return 0;
4019114402Sru}
4020114402Sru
4021114402Sruvoid suppress_node::put(troff_output_file *out, const char *s)
4022114402Sru{
4023114402Sru  int i = 0;
4024114402Sru  while (s[i] != (char)0) {
4025114402Sru    out->special_char(s[i]);
4026114402Sru    i++;
4027114402Sru  }
4028114402Sru}
4029114402Sru
4030114402Sru/*
4031114402Sru *  We need to remember the start of the image and its name.
4032114402Sru */
4033114402Sru
4034114402Srustatic char last_position = 0;
4035114402Srustatic const char *last_image_filename = 0;
4036114402Srustatic int last_image_id = 0;
4037114402Sru
4038114402Sruinline int min(int a, int b)
4039114402Sru{
4040114402Sru  return a < b ? a : b;
4041114402Sru}
4042114402Sru
4043114402Sru/*
4044114402Sru *  tprint - if (is_on == 2)
4045114402Sru *               remember current position (l, r, c, i) and filename
4046114402Sru *           else
4047114402Sru *               if (emit_limits)
4048114402Sru *                   if (html)
4049114402Sru *                      emit image tag
4050114402Sru *                   else
4051114402Sru *                      emit postscript bounds for image
4052114402Sru *               else
4053114402Sru *                  if (suppress boolean differs from current state)
4054114402Sru *                      alter state
4055114402Sru *                  reset registers
4056114402Sru *                  record current page
4057114402Sru *                  set low water mark.
4058114402Sru */
4059114402Sru
4060114402Sruvoid suppress_node::tprint(troff_output_file *out)
4061114402Sru{
4062114402Sru  int current_page = topdiv->get_page_number();
4063114402Sru  // firstly check to see whether this suppress node contains
4064114402Sru  // an image filename & position.
4065114402Sru  if (is_on == 2) {
4066114402Sru    // remember position and filename
4067114402Sru    last_position = position;
4068151497Sru    char *tem = (char *)last_image_filename;
4069114402Sru    last_image_filename = strsave(filename.contents());
4070114402Sru    if (tem)
4071151497Sru      a_delete tem;
4072114402Sru    last_image_id = image_id;
4073114402Sru    // printf("start of image and page = %d\n", current_page);
4074114402Sru  }
4075114402Sru  else {
4076114402Sru    // now check whether the suppress node requires us to issue limits.
4077114402Sru    if (emit_limits) {
4078114402Sru      char name[8192];
4079114402Sru      // remember that the filename will contain a %d in which the
4080114402Sru      // last_image_id is placed
4081151497Sru      if (last_image_filename == (char *) 0)
4082151497Sru	*name = '\0';
4083151497Sru      else
4084151497Sru	sprintf(name, last_image_filename, last_image_id);
4085114402Sru      if (is_html) {
4086114402Sru	switch (last_position) {
4087114402Sru	case 'c':
4088114402Sru	  out->start_special();
4089151497Sru	  put(out, "devtag:.centered-image");
4090114402Sru	  break;
4091114402Sru	case 'r':
4092114402Sru	  out->start_special();
4093151497Sru	  put(out, "devtag:.right-image");
4094114402Sru	  break;
4095114402Sru	case 'l':
4096114402Sru	  out->start_special();
4097151497Sru	  put(out, "devtag:.left-image");
4098114402Sru	  break;
4099114402Sru	case 'i':
4100114402Sru	  ;
4101114402Sru	default:
4102114402Sru	  ;
4103114402Sru	}
4104114402Sru	out->end_special();
4105114402Sru	out->start_special();
4106151497Sru	put(out, "devtag:.auto-image ");
4107114402Sru	put(out, name);
4108114402Sru	out->end_special();
4109114402Sru      }
4110114402Sru      else {
4111114402Sru	// postscript (or other device)
4112114402Sru	if (suppress_start_page > 0 && current_page != suppress_start_page)
4113114402Sru	  error("suppression limit registers span more than one page;\n"
4114114402Sru	        "image description %1 will be wrong", image_no);
4115114402Sru	// if (topdiv->get_page_number() != suppress_start_page)
4116114402Sru	//  fprintf(stderr, "end of image and topdiv page = %d   and  suppress_start_page = %d\n",
4117114402Sru	//	  topdiv->get_page_number(), suppress_start_page);
4118114402Sru
4119114402Sru	// remember that the filename will contain a %d in which the
4120114402Sru	// image_no is placed
4121114402Sru	fprintf(stderr,
4122114402Sru		"grohtml-info:page %d  %d  %d  %d  %d  %d  %s  %d  %d  %s\n",
4123114402Sru		topdiv->get_page_number(),
4124114402Sru		get_reg_int("opminx"), get_reg_int("opminy"),
4125114402Sru		get_reg_int("opmaxx"), get_reg_int("opmaxy"),
4126114402Sru		// page offset + line length
4127114402Sru		get_reg_int(".o") + get_reg_int(".l"),
4128114402Sru		name, hresolution, vresolution, get_reg_str(".F"));
4129114402Sru	fflush(stderr);
4130114402Sru      }
4131114402Sru    }
4132114402Sru    else {
4133114402Sru      if (is_on) {
4134114402Sru	out->on();
4135114402Sru	// lastly we reset the output registers
4136114402Sru	reset_output_registers();
4137114402Sru      }
4138114402Sru      else
4139114402Sru	out->off();
4140114402Sru      suppress_start_page = current_page;
4141114402Sru    }
4142114402Sru  }
4143114402Sru}
4144114402Sru
4145114402Sruint suppress_node::force_tprint()
4146114402Sru{
4147114402Sru  return is_on;
4148114402Sru}
4149114402Sru
4150151497Sruint suppress_node::is_tag()
4151151497Sru{
4152151497Sru  return is_on;
4153151497Sru}
4154151497Sru
4155114402Sruhunits suppress_node::width()
4156114402Sru{
4157114402Sru  return H0;
4158114402Sru}
4159114402Sru
4160114402Sru/* composite_node */
4161114402Sru
4162114402Sruclass composite_node : public charinfo_node {
4163114402Sru  node *n;
4164114402Sru  tfont *tf;
4165114402Srupublic:
4166151497Sru  composite_node(node *, charinfo *, tfont *, statem *, int, node * = 0);
4167114402Sru  ~composite_node();
4168114402Sru  node *copy();
4169114402Sru  hunits width();
4170114402Sru  node *last_char_node();
4171114402Sru  units size();
4172114402Sru  void tprint(troff_output_file *);
4173114402Sru  hyphenation_type get_hyphenation_type();
4174114402Sru  void ascii_print(ascii_output_file *);
4175114402Sru  void asciify(macro *);
4176114402Sru  hyphen_list *get_hyphen_list(hyphen_list *, int *);
4177114402Sru  node *add_self(node *, hyphen_list **);
4178114402Sru  tfont *get_tfont();
4179114402Sru  int same(node *);
4180114402Sru  const char *type();
4181114402Sru  int force_tprint();
4182151497Sru  int is_tag();
4183114402Sru  void vertical_extent(vunits *, vunits *);
4184114402Sru  vunits vertical_width();
4185114402Sru};
4186114402Sru
4187151497Srucomposite_node::composite_node(node *p, charinfo *c, tfont *t, statem *s,
4188151497Sru			       int pop, node *x)
4189151497Sru: charinfo_node(c, s, pop, x), n(p), tf(t)
4190114402Sru{
4191114402Sru}
4192114402Sru
4193114402Srucomposite_node::~composite_node()
4194114402Sru{
4195114402Sru  delete_node_list(n);
4196114402Sru}
4197114402Sru
4198114402Srunode *composite_node::copy()
4199114402Sru{
4200151497Sru  return new composite_node(copy_node_list(n), ci, tf, state, div_nest_level);
4201114402Sru}
4202114402Sru
4203114402Sruhunits composite_node::width()
4204114402Sru{
4205114402Sru  hunits x;
4206114402Sru  if (tf->get_constant_space(&x))
4207114402Sru    return x;
4208114402Sru  x = H0;
4209114402Sru  for (node *tem = n; tem; tem = tem->next)
4210114402Sru    x += tem->width();
4211114402Sru  hunits offset;
4212114402Sru  if (tf->get_bold(&offset))
4213114402Sru    x += offset;
4214114402Sru  x += tf->get_track_kern();
4215114402Sru  return x;
4216114402Sru}
4217114402Sru
4218114402Srunode *composite_node::last_char_node()
4219114402Sru{
4220114402Sru  return this;
4221114402Sru}
4222114402Sru
4223114402Sruvunits composite_node::vertical_width()
4224114402Sru{
4225114402Sru  vunits v = V0;
4226114402Sru  for (node *tem = n; tem; tem = tem->next)
4227114402Sru    v += tem->vertical_width();
4228114402Sru  return v;
4229114402Sru}
4230114402Sru
4231114402Sruunits composite_node::size()
4232114402Sru{
4233114402Sru  return tf->get_size().to_units();
4234114402Sru}
4235114402Sru
4236114402Sruhyphenation_type composite_node::get_hyphenation_type()
4237114402Sru{
4238114402Sru  return HYPHEN_MIDDLE;
4239114402Sru}
4240114402Sru
4241114402Sruvoid composite_node::asciify(macro *m)
4242114402Sru{
4243114402Sru  unsigned char c = ci->get_asciify_code();
4244114402Sru  if (c == 0)
4245114402Sru    c = ci->get_ascii_code();
4246114402Sru  if (c != 0) {
4247114402Sru    m->append(c);
4248114402Sru    delete this;
4249114402Sru  }
4250114402Sru  else
4251114402Sru    m->append(this);
4252114402Sru}
4253114402Sru
4254114402Sruvoid composite_node::ascii_print(ascii_output_file *ascii)
4255114402Sru{
4256114402Sru  unsigned char c = ci->get_ascii_code();
4257114402Sru  if (c != 0)
4258114402Sru    ascii->outc(c);
4259114402Sru  else
4260114402Sru    ascii->outs(ci->nm.contents());
4261114402Sru
4262114402Sru}
4263114402Sru
4264114402Sruhyphen_list *composite_node::get_hyphen_list(hyphen_list *tail, int *count)
4265114402Sru{
4266114402Sru  (*count)++;
4267114402Sru  return new hyphen_list(ci->get_hyphenation_code(), tail);
4268114402Sru}
4269114402Sru
4270114402Srunode *composite_node::add_self(node *nn, hyphen_list **p)
4271114402Sru{
4272114402Sru  assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
4273114402Sru  next = nn;
4274114402Sru  nn = this;
4275114402Sru  if ((*p)->hyphen)
4276114402Sru    nn = nn->add_discretionary_hyphen();
4277114402Sru  hyphen_list *pp = *p;
4278114402Sru  *p = (*p)->next;
4279114402Sru  delete pp;
4280114402Sru  return nn;
4281114402Sru}
4282114402Sru
4283114402Srutfont *composite_node::get_tfont()
4284114402Sru{
4285114402Sru  return tf;
4286114402Sru}
4287114402Sru
4288114402Srunode *reverse_node_list(node *n)
4289114402Sru{
4290114402Sru  node *r = 0;
4291114402Sru  while (n) {
4292114402Sru    node *tem = n;
4293114402Sru    n = n->next;
4294114402Sru    tem->next = r;
4295114402Sru    r = tem;
4296114402Sru  }
4297114402Sru  return r;
4298114402Sru}
4299114402Sru
4300151497Sruvoid composite_node::vertical_extent(vunits *minimum, vunits *maximum)
4301114402Sru{
4302114402Sru  n = reverse_node_list(n);
4303151497Sru  node_list_vertical_extent(n, minimum, maximum);
4304114402Sru  n = reverse_node_list(n);
4305114402Sru}
4306114402Sru
4307114402Sruwidth_list::width_list(hunits w, hunits s)
4308114402Sru: width(w), sentence_width(s), next(0)
4309114402Sru{
4310114402Sru}
4311114402Sru
4312114402Sruwidth_list::width_list(width_list *w)
4313114402Sru: width(w->width), sentence_width(w->sentence_width), next(0)
4314114402Sru{
4315114402Sru}
4316114402Sru
4317114402Sruword_space_node::word_space_node(hunits d, color *c, width_list *w, node *x)
4318114402Sru: space_node(d, c, x), orig_width(w), unformat(0)
4319114402Sru{
4320114402Sru}
4321114402Sru
4322114402Sruword_space_node::word_space_node(hunits d, int s, color *c, width_list *w,
4323151497Sru				 int flag, statem *st, int pop, node *x)
4324151497Sru: space_node(d, s, 0, c, st, pop, x), orig_width(w), unformat(flag)
4325114402Sru{
4326114402Sru}
4327114402Sru
4328114402Sruword_space_node::~word_space_node()
4329114402Sru{
4330114402Sru  width_list *w = orig_width;
4331114402Sru  while (w != 0) {
4332114402Sru    width_list *tmp = w;
4333114402Sru    w = w->next;
4334114402Sru    delete tmp;
4335114402Sru  }
4336114402Sru}
4337114402Sru
4338114402Srunode *word_space_node::copy()
4339114402Sru{
4340114402Sru  assert(orig_width != 0);
4341114402Sru  width_list *w_old_curr = orig_width;
4342114402Sru  width_list *w_new_curr = new width_list(w_old_curr);
4343114402Sru  width_list *w_new = w_new_curr;
4344114402Sru  w_old_curr = w_old_curr->next;
4345114402Sru  while (w_old_curr != 0) {
4346114402Sru    w_new_curr->next = new width_list(w_old_curr);
4347114402Sru    w_new_curr = w_new_curr->next;
4348114402Sru    w_old_curr = w_old_curr->next;
4349114402Sru  }
4350151497Sru  return new word_space_node(n, set, col, w_new, unformat, state,
4351151497Sru			     div_nest_level);
4352114402Sru}
4353114402Sru
4354114402Sruint word_space_node::set_unformat_flag()
4355114402Sru{
4356114402Sru  unformat = 1;
4357114402Sru  return 1;
4358114402Sru}
4359114402Sru
4360114402Sruvoid word_space_node::tprint(troff_output_file *out)
4361114402Sru{
4362114402Sru  out->fill_color(col);
4363114402Sru  out->word_marker();
4364114402Sru  out->right(n);
4365114402Sru}
4366114402Sru
4367114402Sruint word_space_node::merge_space(hunits h, hunits sw, hunits ssw)
4368114402Sru{
4369114402Sru  n += h;
4370114402Sru  assert(orig_width != 0);
4371114402Sru  width_list *w = orig_width;
4372114402Sru  for (; w->next; w = w->next)
4373114402Sru    ;
4374114402Sru  w->next = new width_list(sw, ssw);
4375114402Sru  return 1;
4376114402Sru}
4377114402Sru
4378114402Sruunbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x)
4379114402Sru: word_space_node(d, c, 0, x)
4380114402Sru{
4381114402Sru}
4382114402Sru
4383114402Sruunbreakable_space_node::unbreakable_space_node(hunits d, int s,
4384151497Sru					       color *c, statem *st, int pop,
4385151497Sru					       node *x)
4386151497Sru: word_space_node(d, s, c, 0, 0, st, pop, x)
4387114402Sru{
4388114402Sru}
4389114402Sru
4390114402Srunode *unbreakable_space_node::copy()
4391114402Sru{
4392151497Sru  return new unbreakable_space_node(n, set, col, state, div_nest_level);
4393114402Sru}
4394114402Sru
4395114402Sruint unbreakable_space_node::force_tprint()
4396114402Sru{
4397114402Sru  return 0;
4398114402Sru}
4399114402Sru
4400151497Sruint unbreakable_space_node::is_tag()
4401151497Sru{
4402151497Sru  return 0;
4403151497Sru}
4404151497Sru
4405114402Srubreakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
4406114402Sru						    breakpoint *rest, int)
4407114402Sru{
4408114402Sru  return rest;
4409114402Sru}
4410114402Sru
4411114402Sruint unbreakable_space_node::nbreaks()
4412114402Sru{
4413114402Sru  return 0;
4414114402Sru}
4415114402Sru
4416114402Sruvoid unbreakable_space_node::split(int, node **, node **)
4417114402Sru{
4418114402Sru  assert(0);
4419114402Sru}
4420114402Sru
4421114402Sruint unbreakable_space_node::merge_space(hunits, hunits, hunits)
4422114402Sru{
4423114402Sru  return 0;
4424114402Sru}
4425114402Sru
4426114402Sruhvpair::hvpair()
4427114402Sru{
4428114402Sru}
4429114402Sru
4430114402Srudraw_node::draw_node(char c, hvpair *p, int np, font_size s,
4431114402Sru		     color *gc, color *fc)
4432114402Sru: npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4433114402Sru{
4434114402Sru  point = new hvpair[npoints];
4435114402Sru  for (int i = 0; i < npoints; i++)
4436114402Sru    point[i] = p[i];
4437114402Sru}
4438114402Sru
4439151497Srudraw_node::draw_node(char c, hvpair *p, int np, font_size s,
4440151497Sru		     color *gc, color *fc, statem *st, int pop)
4441151497Sru: node(0, st, pop), npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4442151497Sru{
4443151497Sru  point = new hvpair[npoints];
4444151497Sru  for (int i = 0; i < npoints; i++)
4445151497Sru    point[i] = p[i];
4446151497Sru}
4447151497Sru
4448114402Sruint draw_node::same(node *n)
4449114402Sru{
4450114402Sru  draw_node *nd = (draw_node *)n;
4451114402Sru  if (code != nd->code || npoints != nd->npoints || sz != nd->sz
4452114402Sru      || gcol != nd->gcol || fcol != nd->fcol)
4453114402Sru    return 0;
4454114402Sru  for (int i = 0; i < npoints; i++)
4455114402Sru    if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
4456114402Sru      return 0;
4457114402Sru  return 1;
4458114402Sru}
4459114402Sru
4460114402Sruconst char *draw_node::type()
4461114402Sru{
4462114402Sru  return "draw_node";
4463114402Sru}
4464114402Sru
4465114402Sruint draw_node::force_tprint()
4466114402Sru{
4467114402Sru  return 0;
4468114402Sru}
4469114402Sru
4470151497Sruint draw_node::is_tag()
4471151497Sru{
4472151497Sru  return 0;
4473151497Sru}
4474151497Sru
4475114402Srudraw_node::~draw_node()
4476114402Sru{
4477114402Sru  if (point)
4478114402Sru    a_delete point;
4479114402Sru}
4480114402Sru
4481114402Sruhunits draw_node::width()
4482114402Sru{
4483114402Sru  hunits x = H0;
4484114402Sru  for (int i = 0; i < npoints; i++)
4485114402Sru    x += point[i].h;
4486114402Sru  return x;
4487114402Sru}
4488114402Sru
4489114402Sruvunits draw_node::vertical_width()
4490114402Sru{
4491114402Sru  if (code == 'e')
4492114402Sru    return V0;
4493114402Sru  vunits x = V0;
4494114402Sru  for (int i = 0; i < npoints; i++)
4495114402Sru    x += point[i].v;
4496114402Sru  return x;
4497114402Sru}
4498114402Sru
4499114402Srunode *draw_node::copy()
4500114402Sru{
4501151497Sru  return new draw_node(code, point, npoints, sz, gcol, fcol, state,
4502151497Sru		       div_nest_level);
4503114402Sru}
4504114402Sru
4505114402Sruvoid draw_node::tprint(troff_output_file *out)
4506114402Sru{
4507114402Sru  out->draw(code, point, npoints, sz, gcol, fcol);
4508114402Sru}
4509114402Sru
4510114402Sru/* tprint methods */
4511114402Sru
4512114402Sruvoid glyph_node::tprint(troff_output_file *out)
4513114402Sru{
4514114402Sru  tfont *ptf = tf->get_plain();
4515114402Sru  if (ptf == tf)
4516114402Sru    out->put_char_width(ci, ptf, gcol, fcol, width(), H0);
4517114402Sru  else {
4518114402Sru    hunits offset;
4519114402Sru    int bold = tf->get_bold(&offset);
4520114402Sru    hunits w = ptf->get_width(ci);
4521114402Sru    hunits k = H0;
4522114402Sru    hunits x;
4523114402Sru    int cs = tf->get_constant_space(&x);
4524114402Sru    if (cs) {
4525114402Sru      x -= w;
4526114402Sru      if (bold)
4527114402Sru	x -= offset;
4528114402Sru      hunits x2 = x/2;
4529114402Sru      out->right(x2);
4530114402Sru      k = x - x2;
4531114402Sru    }
4532114402Sru    else
4533114402Sru      k = tf->get_track_kern();
4534114402Sru    if (bold) {
4535114402Sru      out->put_char(ci, ptf, gcol, fcol);
4536114402Sru      out->right(offset);
4537114402Sru    }
4538114402Sru    out->put_char_width(ci, ptf, gcol, fcol, w, k);
4539114402Sru  }
4540114402Sru}
4541114402Sru
4542114402Sruvoid glyph_node::zero_width_tprint(troff_output_file *out)
4543114402Sru{
4544114402Sru  tfont *ptf = tf->get_plain();
4545114402Sru  hunits offset;
4546114402Sru  int bold = tf->get_bold(&offset);
4547114402Sru  hunits x;
4548114402Sru  int cs = tf->get_constant_space(&x);
4549114402Sru  if (cs) {
4550114402Sru    x -= ptf->get_width(ci);
4551114402Sru    if (bold)
4552114402Sru      x -= offset;
4553114402Sru    x = x/2;
4554114402Sru    out->right(x);
4555114402Sru  }
4556114402Sru  out->put_char(ci, ptf, gcol, fcol);
4557114402Sru  if (bold) {
4558114402Sru    out->right(offset);
4559114402Sru    out->put_char(ci, ptf, gcol, fcol);
4560114402Sru    out->right(-offset);
4561114402Sru  }
4562114402Sru  if (cs)
4563114402Sru    out->right(-x);
4564114402Sru}
4565114402Sru
4566114402Sruvoid break_char_node::tprint(troff_output_file *t)
4567114402Sru{
4568114402Sru  ch->tprint(t);
4569114402Sru}
4570114402Sru
4571114402Sruvoid break_char_node::zero_width_tprint(troff_output_file *t)
4572114402Sru{
4573114402Sru  ch->zero_width_tprint(t);
4574114402Sru}
4575114402Sru
4576114402Sruvoid hline_node::tprint(troff_output_file *out)
4577114402Sru{
4578114402Sru  if (x < H0) {
4579114402Sru    out->right(x);
4580114402Sru    x = -x;
4581114402Sru  }
4582114402Sru  if (n == 0) {
4583114402Sru    out->right(x);
4584114402Sru    return;
4585114402Sru  }
4586114402Sru  hunits w = n->width();
4587114402Sru  if (w <= H0) {
4588114402Sru    error("horizontal line drawing character must have positive width");
4589114402Sru    out->right(x);
4590114402Sru    return;
4591114402Sru  }
4592114402Sru  int i = int(x/w);
4593114402Sru  if (i == 0) {
4594114402Sru    hunits xx = x - w;
4595114402Sru    hunits xx2 = xx/2;
4596114402Sru    out->right(xx2);
4597114402Sru    if (out->is_on())
4598114402Sru      n->tprint(out);
4599114402Sru    out->right(xx - xx2);
4600114402Sru  }
4601114402Sru  else {
4602114402Sru    hunits rem = x - w*i;
4603257263Ssbruno    if (rem > H0) {
4604114402Sru      if (n->overlaps_horizontally()) {
4605114402Sru	if (out->is_on())
4606114402Sru	  n->tprint(out);
4607114402Sru	out->right(rem - w);
4608257263Ssbruno      } else
4609114402Sru	out->right(rem);
4610257263Ssbruno    }
4611114402Sru    while (--i >= 0)
4612114402Sru      if (out->is_on())
4613114402Sru	n->tprint(out);
4614114402Sru  }
4615114402Sru}
4616114402Sru
4617114402Sruvoid vline_node::tprint(troff_output_file *out)
4618114402Sru{
4619114402Sru  if (n == 0) {
4620114402Sru    out->down(x);
4621114402Sru    return;
4622114402Sru  }
4623114402Sru  vunits h = n->size();
4624114402Sru  int overlaps = n->overlaps_vertically();
4625114402Sru  vunits y = x;
4626114402Sru  if (y < V0) {
4627114402Sru    y = -y;
4628114402Sru    int i = y / h;
4629114402Sru    vunits rem = y - i*h;
4630114402Sru    if (i == 0) {
4631114402Sru      out->right(n->width());
4632114402Sru      out->down(-rem);
4633114402Sru    }
4634114402Sru    else {
4635114402Sru      while (--i > 0) {
4636114402Sru	n->zero_width_tprint(out);
4637114402Sru	out->down(-h);
4638114402Sru      }
4639114402Sru      if (overlaps) {
4640114402Sru	n->zero_width_tprint(out);
4641114402Sru	out->down(-rem);
4642114402Sru	if (out->is_on())
4643114402Sru	  n->tprint(out);
4644114402Sru	out->down(-h);
4645114402Sru      }
4646114402Sru      else {
4647114402Sru	if (out->is_on())
4648114402Sru	  n->tprint(out);
4649114402Sru	out->down(-h - rem);
4650114402Sru      }
4651114402Sru    }
4652114402Sru  }
4653114402Sru  else {
4654114402Sru    int i = y / h;
4655114402Sru    vunits rem = y - i*h;
4656114402Sru    if (i == 0) {
4657114402Sru      out->down(rem);
4658114402Sru      out->right(n->width());
4659114402Sru    }
4660114402Sru    else {
4661114402Sru      out->down(h);
4662114402Sru      if (overlaps)
4663114402Sru	n->zero_width_tprint(out);
4664114402Sru      out->down(rem);
4665114402Sru      while (--i > 0) {
4666114402Sru	n->zero_width_tprint(out);
4667114402Sru	out->down(h);
4668114402Sru      }
4669114402Sru      if (out->is_on())
4670114402Sru	n->tprint(out);
4671114402Sru    }
4672114402Sru  }
4673114402Sru}
4674114402Sru
4675114402Sruvoid zero_width_node::tprint(troff_output_file *out)
4676114402Sru{
4677114402Sru  if (!n)
4678114402Sru    return;
4679114402Sru  if (!n->next) {
4680114402Sru    n->zero_width_tprint(out);
4681114402Sru    return;
4682114402Sru  }
4683114402Sru  int hpos = out->get_hpos();
4684114402Sru  int vpos = out->get_vpos();
4685114402Sru  node *tem = n;
4686114402Sru  while (tem) {
4687114402Sru    tem->tprint(out);
4688114402Sru    tem = tem->next;
4689114402Sru  }
4690114402Sru  out->moveto(hpos, vpos);
4691114402Sru}
4692114402Sru
4693114402Sruvoid overstrike_node::tprint(troff_output_file *out)
4694114402Sru{
4695114402Sru  hunits pos = H0;
4696114402Sru  for (node *tem = list; tem; tem = tem->next) {
4697114402Sru    hunits x = (max_width - tem->width())/2;
4698114402Sru    out->right(x - pos);
4699114402Sru    pos = x;
4700114402Sru    tem->zero_width_tprint(out);
4701114402Sru  }
4702114402Sru  out->right(max_width - pos);
4703114402Sru}
4704114402Sru
4705114402Sruvoid bracket_node::tprint(troff_output_file *out)
4706114402Sru{
4707114402Sru  if (list == 0)
4708114402Sru    return;
4709114402Sru  int npieces = 0;
4710114402Sru  node *tem;
4711114402Sru  for (tem = list; tem; tem = tem->next)
4712114402Sru    ++npieces;
4713114402Sru  vunits h = list->size();
4714114402Sru  vunits totalh = h*npieces;
4715114402Sru  vunits y = (totalh - h)/2;
4716114402Sru  out->down(y);
4717114402Sru  for (tem = list; tem; tem = tem->next) {
4718114402Sru    tem->zero_width_tprint(out);
4719114402Sru    out->down(-h);
4720114402Sru  }
4721114402Sru  out->right(max_width);
4722114402Sru  out->down(totalh - y);
4723114402Sru}
4724114402Sru
4725114402Sruvoid node::tprint(troff_output_file *)
4726114402Sru{
4727114402Sru}
4728114402Sru
4729114402Sruvoid node::zero_width_tprint(troff_output_file *out)
4730114402Sru{
4731114402Sru  int hpos = out->get_hpos();
4732114402Sru  int vpos = out->get_vpos();
4733114402Sru  tprint(out);
4734114402Sru  out->moveto(hpos, vpos);
4735114402Sru}
4736114402Sru
4737114402Sruvoid space_node::tprint(troff_output_file *out)
4738114402Sru{
4739114402Sru  out->fill_color(col);
4740114402Sru  out->right(n);
4741114402Sru}
4742114402Sru
4743114402Sruvoid hmotion_node::tprint(troff_output_file *out)
4744114402Sru{
4745114402Sru  out->fill_color(col);
4746114402Sru  out->right(n);
4747114402Sru}
4748114402Sru
4749114402Sruvoid space_char_hmotion_node::tprint(troff_output_file *out)
4750114402Sru{
4751114402Sru  out->fill_color(col);
4752114402Sru  if (is_html) {
4753114402Sru    // we emit the space width as a negative glyph index
4754114402Sru    out->flush_tbuf();
4755114402Sru    out->do_motion();
4756114402Sru    out->put('N');
4757114402Sru    out->put(-n.to_units());
4758114402Sru    out->put('\n');
4759114402Sru  }
4760114402Sru  out->right(n);
4761114402Sru}
4762114402Sru
4763114402Sruvoid vmotion_node::tprint(troff_output_file *out)
4764114402Sru{
4765114402Sru  out->fill_color(col);
4766114402Sru  out->down(n);
4767114402Sru}
4768114402Sru
4769114402Sruvoid kern_pair_node::tprint(troff_output_file *out)
4770114402Sru{
4771114402Sru  n1->tprint(out);
4772114402Sru  out->right(amount);
4773114402Sru  n2->tprint(out);
4774114402Sru}
4775114402Sru
4776114402Srustatic void tprint_reverse_node_list(troff_output_file *out, node *n)
4777114402Sru{
4778114402Sru  if (n == 0)
4779114402Sru    return;
4780114402Sru  tprint_reverse_node_list(out, n->next);
4781114402Sru  n->tprint(out);
4782114402Sru}
4783114402Sru
4784114402Sruvoid dbreak_node::tprint(troff_output_file *out)
4785114402Sru{
4786114402Sru  tprint_reverse_node_list(out, none);
4787114402Sru}
4788114402Sru
4789114402Sruvoid composite_node::tprint(troff_output_file *out)
4790114402Sru{
4791114402Sru  hunits bold_offset;
4792114402Sru  int is_bold = tf->get_bold(&bold_offset);
4793114402Sru  hunits track_kern = tf->get_track_kern();
4794114402Sru  hunits constant_space;
4795114402Sru  int is_constant_spaced = tf->get_constant_space(&constant_space);
4796114402Sru  hunits x = H0;
4797114402Sru  if (is_constant_spaced) {
4798114402Sru    x = constant_space;
4799114402Sru    for (node *tem = n; tem; tem = tem->next)
4800114402Sru      x -= tem->width();
4801114402Sru    if (is_bold)
4802114402Sru      x -= bold_offset;
4803114402Sru    hunits x2 = x/2;
4804114402Sru    out->right(x2);
4805114402Sru    x -= x2;
4806114402Sru  }
4807114402Sru  if (is_bold) {
4808114402Sru    int hpos = out->get_hpos();
4809114402Sru    int vpos = out->get_vpos();
4810114402Sru    tprint_reverse_node_list(out, n);
4811114402Sru    out->moveto(hpos, vpos);
4812114402Sru    out->right(bold_offset);
4813114402Sru  }
4814114402Sru  tprint_reverse_node_list(out, n);
4815114402Sru  if (is_constant_spaced)
4816114402Sru    out->right(x);
4817114402Sru  else
4818114402Sru    out->right(track_kern);
4819114402Sru}
4820114402Sru
4821114402Srunode *make_composite_node(charinfo *s, environment *env)
4822114402Sru{
4823114402Sru  int fontno = env_definite_font(env);
4824114402Sru  if (fontno < 0) {
4825114402Sru    error("no current font");
4826114402Sru    return 0;
4827114402Sru  }
4828114402Sru  assert(fontno < font_table_size && font_table[fontno] != 0);
4829114402Sru  node *n = charinfo_to_node_list(s, env);
4830114402Sru  font_size fs = env->get_font_size();
4831114402Sru  int char_height = env->get_char_height();
4832114402Sru  int char_slant = env->get_char_slant();
4833114402Sru  tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
4834114402Sru					    fontno);
4835114402Sru  if (env->is_composite())
4836114402Sru    tf = tf->get_plain();
4837151497Sru  return new composite_node(n, s, tf, 0, 0, 0);
4838114402Sru}
4839114402Sru
4840114402Srunode *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
4841114402Sru{
4842114402Sru  int fontno = env_definite_font(env);
4843114402Sru  if (fontno < 0) {
4844114402Sru    error("no current font");
4845114402Sru    return 0;
4846114402Sru  }
4847114402Sru  assert(fontno < font_table_size && font_table[fontno] != 0);
4848114402Sru  int fn = fontno;
4849114402Sru  int found = font_table[fontno]->contains(s);
4850114402Sru  if (!found) {
4851114402Sru    macro *mac = s->get_macro();
4852114402Sru    if (mac && s->is_fallback())
4853114402Sru      return make_composite_node(s, env);
4854114402Sru    if (s->numbered()) {
4855114402Sru      if (!no_error_message)
4856114402Sru	warning(WARN_CHAR, "can't find numbered character %1",
4857114402Sru		s->get_number());
4858114402Sru      return 0;
4859114402Sru    }
4860114402Sru    special_font_list *sf = font_table[fontno]->sf;
4861114402Sru    while (sf != 0 && !found) {
4862114402Sru      fn = sf->n;
4863114402Sru      if (font_table[fn])
4864114402Sru	found = font_table[fn]->contains(s);
4865114402Sru      sf = sf->next;
4866114402Sru    }
4867114402Sru    if (!found) {
4868114402Sru      symbol f = font_table[fontno]->get_name();
4869114402Sru      string gl(f.contents());
4870114402Sru      gl += ' ';
4871114402Sru      gl += s->nm.contents();
4872114402Sru      gl += '\0';
4873114402Sru      charinfo *ci = get_charinfo(symbol(gl.contents()));
4874114402Sru      if (ci && ci->get_macro())
4875114402Sru	return make_composite_node(ci, env);
4876114402Sru    }
4877114402Sru    if (!found) {
4878114402Sru      sf = global_special_fonts;
4879114402Sru      while (sf != 0 && !found) {
4880114402Sru	fn = sf->n;
4881114402Sru	if (font_table[fn])
4882114402Sru	  found = font_table[fn]->contains(s);
4883114402Sru	sf = sf->next;
4884114402Sru      }
4885114402Sru    }
4886114402Sru    if (!found)
4887114402Sru      if (mac && s->is_special())
4888114402Sru	return make_composite_node(s, env);
4889114402Sru    if (!found) {
4890114402Sru      for (fn = 0; fn < font_table_size; fn++)
4891114402Sru	if (font_table[fn]
4892114402Sru	    && font_table[fn]->is_special()
4893114402Sru	    && font_table[fn]->contains(s)) {
4894114402Sru	  found = 1;
4895114402Sru	  break;
4896114402Sru	}
4897114402Sru    }
4898114402Sru    if (!found) {
4899114402Sru      if (!no_error_message && s->first_time_not_found()) {
4900114402Sru	unsigned char input_code = s->get_ascii_code();
4901114402Sru	if (input_code != 0) {
4902114402Sru	  if (csgraph(input_code))
4903114402Sru	    warning(WARN_CHAR, "can't find character `%1'", input_code);
4904114402Sru	  else
4905114402Sru	    warning(WARN_CHAR, "can't find character with input code %1",
4906114402Sru		    int(input_code));
4907114402Sru	}
4908114402Sru	else if (s->nm.contents())
4909114402Sru	  warning(WARN_CHAR, "can't find special character `%1'",
4910114402Sru		  s->nm.contents());
4911114402Sru      }
4912114402Sru      return 0;
4913114402Sru    }
4914114402Sru  }
4915114402Sru  font_size fs = env->get_font_size();
4916114402Sru  int char_height = env->get_char_height();
4917114402Sru  int char_slant = env->get_char_slant();
4918114402Sru  tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
4919114402Sru  if (env->is_composite())
4920114402Sru    tf = tf->get_plain();
4921114402Sru  color *gcol = env->get_glyph_color();
4922114402Sru  color *fcol = env->get_fill_color();
4923151497Sru  return new glyph_node(s, tf, gcol, fcol, 0, 0);
4924114402Sru}
4925114402Sru
4926114402Srunode *make_node(charinfo *ci, environment *env)
4927114402Sru{
4928114402Sru  switch (ci->get_special_translation()) {
4929114402Sru  case charinfo::TRANSLATE_SPACE:
4930114402Sru    return new space_char_hmotion_node(env->get_space_width(),
4931114402Sru				       env->get_fill_color());
4932114402Sru  case charinfo::TRANSLATE_STRETCHABLE_SPACE:
4933114402Sru    return new unbreakable_space_node(env->get_space_width(),
4934114402Sru				      env->get_fill_color());
4935114402Sru  case charinfo::TRANSLATE_DUMMY:
4936114402Sru    return new dummy_node;
4937114402Sru  case charinfo::TRANSLATE_HYPHEN_INDICATOR:
4938114402Sru    error("translation to \\% ignored in this context");
4939114402Sru    break;
4940114402Sru  }
4941114402Sru  charinfo *tem = ci->get_translation();
4942114402Sru  if (tem)
4943114402Sru    ci = tem;
4944114402Sru  macro *mac = ci->get_macro();
4945114402Sru  if (mac && ci->is_normal())
4946114402Sru    return make_composite_node(ci, env);
4947114402Sru  else
4948114402Sru    return make_glyph_node(ci, env);
4949114402Sru}
4950114402Sru
4951114402Sruint character_exists(charinfo *ci, environment *env)
4952114402Sru{
4953114402Sru  if (ci->get_special_translation() != charinfo::TRANSLATE_NONE)
4954114402Sru    return 1;
4955114402Sru  charinfo *tem = ci->get_translation();
4956114402Sru  if (tem)
4957114402Sru    ci = tem;
4958114402Sru  if (ci->get_macro())
4959114402Sru    return 1;
4960114402Sru  node *nd = make_glyph_node(ci, env, 1);
4961114402Sru  if (nd) {
4962114402Sru    delete nd;
4963114402Sru    return 1;
4964114402Sru  }
4965114402Sru  return 0;
4966114402Sru}
4967114402Sru
4968114402Srunode *node::add_char(charinfo *ci, environment *env,
4969151497Sru		     hunits *widthp, int *spacep, node **glyph_comp_np)
4970114402Sru{
4971114402Sru  node *res;
4972114402Sru  switch (ci->get_special_translation()) {
4973114402Sru  case charinfo::TRANSLATE_SPACE:
4974114402Sru    res = new space_char_hmotion_node(env->get_space_width(),
4975114402Sru				      env->get_fill_color(), this);
4976114402Sru    *widthp += res->width();
4977114402Sru    return res;
4978114402Sru  case charinfo::TRANSLATE_STRETCHABLE_SPACE:
4979114402Sru    res = new unbreakable_space_node(env->get_space_width(),
4980114402Sru				     env->get_fill_color(), this);
4981114402Sru    res->freeze_space();
4982114402Sru    *widthp += res->width();
4983114402Sru    *spacep += res->nspaces();
4984114402Sru    return res;
4985114402Sru  case charinfo::TRANSLATE_DUMMY:
4986114402Sru    return new dummy_node(this);
4987114402Sru  case charinfo::TRANSLATE_HYPHEN_INDICATOR:
4988114402Sru    return add_discretionary_hyphen();
4989114402Sru  }
4990114402Sru  charinfo *tem = ci->get_translation();
4991114402Sru  if (tem)
4992114402Sru    ci = tem;
4993114402Sru  macro *mac = ci->get_macro();
4994114402Sru  if (mac && ci->is_normal()) {
4995114402Sru    res = make_composite_node(ci, env);
4996114402Sru    if (res) {
4997114402Sru      res->next = this;
4998114402Sru      *widthp += res->width();
4999151497Sru      if (glyph_comp_np)
5000151497Sru	*glyph_comp_np = res;
5001114402Sru    }
5002151497Sru    else {
5003151497Sru      if (glyph_comp_np)
5004151497Sru	*glyph_comp_np = res;
5005114402Sru      return this;
5006151497Sru    }
5007114402Sru  }
5008114402Sru  else {
5009114402Sru    node *gn = make_glyph_node(ci, env);
5010114402Sru    if (gn == 0)
5011114402Sru      return this;
5012114402Sru    else {
5013114402Sru      hunits old_width = width();
5014114402Sru      node *p = gn->merge_self(this);
5015114402Sru      if (p == 0) {
5016114402Sru	*widthp += gn->width();
5017114402Sru	gn->next = this;
5018114402Sru	res = gn;
5019114402Sru      }
5020114402Sru      else {
5021114402Sru	*widthp += p->width() - old_width;
5022114402Sru	res = p;
5023114402Sru      }
5024151497Sru      if (glyph_comp_np)
5025151497Sru	*glyph_comp_np = res;
5026114402Sru    }
5027114402Sru  }
5028114402Sru  int break_code = 0;
5029114402Sru  if (ci->can_break_before())
5030114402Sru    break_code = 1;
5031114402Sru  if (ci->can_break_after())
5032114402Sru    break_code |= 2;
5033114402Sru  if (break_code) {
5034114402Sru    node *next1 = res->next;
5035114402Sru    res->next = 0;
5036114402Sru    res = new break_char_node(res, break_code, env->get_fill_color(), next1);
5037114402Sru  }
5038114402Sru  return res;
5039114402Sru}
5040114402Sru
5041114402Sru#ifdef __GNUG__
5042114402Sruinline
5043114402Sru#endif
5044114402Sruint same_node(node *n1, node *n2)
5045114402Sru{
5046114402Sru  if (n1 != 0) {
5047114402Sru    if (n2 != 0)
5048114402Sru      return n1->type() == n2->type() && n1->same(n2);
5049114402Sru    else
5050114402Sru      return 0;
5051114402Sru  }
5052114402Sru  else
5053114402Sru    return n2 == 0;
5054114402Sru}
5055114402Sru
5056114402Sruint same_node_list(node *n1, node *n2)
5057114402Sru{
5058114402Sru  while (n1 && n2) {
5059114402Sru    if (n1->type() != n2->type() || !n1->same(n2))
5060114402Sru      return 0;
5061114402Sru    n1 = n1->next;
5062114402Sru    n2 = n2->next;
5063114402Sru  }
5064114402Sru  return !n1 && !n2;
5065114402Sru}
5066114402Sru
5067114402Sruint extra_size_node::same(node *nd)
5068114402Sru{
5069114402Sru  return n == ((extra_size_node *)nd)->n;
5070114402Sru}
5071114402Sru
5072114402Sruconst char *extra_size_node::type()
5073114402Sru{
5074114402Sru  return "extra_size_node";
5075114402Sru}
5076114402Sru
5077114402Sruint extra_size_node::force_tprint()
5078114402Sru{
5079114402Sru  return 0;
5080114402Sru}
5081114402Sru
5082151497Sruint extra_size_node::is_tag()
5083151497Sru{
5084151497Sru  return 0;
5085151497Sru}
5086151497Sru
5087114402Sruint vertical_size_node::same(node *nd)
5088114402Sru{
5089114402Sru  return n == ((vertical_size_node *)nd)->n;
5090114402Sru}
5091114402Sru
5092114402Sruconst char *vertical_size_node::type()
5093114402Sru{
5094114402Sru  return "vertical_size_node";
5095114402Sru}
5096114402Sru
5097114402Sruint vertical_size_node::set_unformat_flag()
5098114402Sru{
5099114402Sru  return 0;
5100114402Sru}
5101114402Sru
5102114402Sruint vertical_size_node::force_tprint()
5103114402Sru{
5104114402Sru  return 0;
5105114402Sru}
5106114402Sru
5107151497Sruint vertical_size_node::is_tag()
5108151497Sru{
5109151497Sru  return 0;
5110151497Sru}
5111151497Sru
5112114402Sruint hmotion_node::same(node *nd)
5113114402Sru{
5114114402Sru  return n == ((hmotion_node *)nd)->n
5115114402Sru	 && col == ((hmotion_node *)nd)->col;
5116114402Sru}
5117114402Sru
5118114402Sruconst char *hmotion_node::type()
5119114402Sru{
5120114402Sru  return "hmotion_node";
5121114402Sru}
5122114402Sru
5123114402Sruint hmotion_node::set_unformat_flag()
5124114402Sru{
5125114402Sru  unformat = 1;
5126114402Sru  return 1;
5127114402Sru}
5128114402Sru
5129114402Sruint hmotion_node::force_tprint()
5130114402Sru{
5131114402Sru  return 0;
5132114402Sru}
5133114402Sru
5134151497Sruint hmotion_node::is_tag()
5135114402Sru{
5136151497Sru  return 0;
5137151497Sru}
5138151497Sru
5139151497Srunode *hmotion_node::add_self(node *nd, hyphen_list **p)
5140151497Sru{
5141151497Sru  next = nd;
5142114402Sru  hyphen_list *pp = *p;
5143114402Sru  *p = (*p)->next;
5144114402Sru  delete pp;
5145114402Sru  return this;
5146114402Sru}
5147114402Sru
5148114402Sruhyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail, int *)
5149114402Sru{
5150114402Sru  return new hyphen_list(0, tail);
5151114402Sru}
5152114402Sru
5153114402Sruint space_char_hmotion_node::same(node *nd)
5154114402Sru{
5155114402Sru  return n == ((space_char_hmotion_node *)nd)->n
5156114402Sru	 && col == ((space_char_hmotion_node *)nd)->col;
5157114402Sru}
5158114402Sru
5159114402Sruconst char *space_char_hmotion_node::type()
5160114402Sru{
5161114402Sru  return "space_char_hmotion_node";
5162114402Sru}
5163114402Sru
5164114402Sruint space_char_hmotion_node::force_tprint()
5165114402Sru{
5166114402Sru  return 0;
5167114402Sru}
5168114402Sru
5169151497Sruint space_char_hmotion_node::is_tag()
5170114402Sru{
5171151497Sru  return 0;
5172151497Sru}
5173151497Sru
5174151497Srunode *space_char_hmotion_node::add_self(node *nd, hyphen_list **p)
5175151497Sru{
5176151497Sru  next = nd;
5177114402Sru  hyphen_list *pp = *p;
5178114402Sru  *p = (*p)->next;
5179114402Sru  delete pp;
5180114402Sru  return this;
5181114402Sru}
5182114402Sru
5183114402Sruhyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail,
5184114402Sru						      int *)
5185114402Sru{
5186114402Sru  return new hyphen_list(0, tail);
5187114402Sru}
5188114402Sru
5189114402Sruint vmotion_node::same(node *nd)
5190114402Sru{
5191114402Sru  return n == ((vmotion_node *)nd)->n
5192114402Sru	 && col == ((vmotion_node *)nd)->col;
5193114402Sru}
5194114402Sru
5195114402Sruconst char *vmotion_node::type()
5196114402Sru{
5197114402Sru  return "vmotion_node";
5198114402Sru}
5199114402Sru
5200114402Sruint vmotion_node::force_tprint()
5201114402Sru{
5202114402Sru  return 0;
5203114402Sru}
5204114402Sru
5205151497Sruint vmotion_node::is_tag()
5206151497Sru{
5207151497Sru  return 0;
5208151497Sru}
5209151497Sru
5210114402Sruint hline_node::same(node *nd)
5211114402Sru{
5212114402Sru  return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
5213114402Sru}
5214114402Sru
5215114402Sruconst char *hline_node::type()
5216114402Sru{
5217114402Sru  return "hline_node";
5218114402Sru}
5219114402Sru
5220114402Sruint hline_node::force_tprint()
5221114402Sru{
5222114402Sru  return 0;
5223114402Sru}
5224114402Sru
5225151497Sruint hline_node::is_tag()
5226151497Sru{
5227151497Sru  return 0;
5228151497Sru}
5229151497Sru
5230114402Sruint vline_node::same(node *nd)
5231114402Sru{
5232114402Sru  return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
5233114402Sru}
5234114402Sru
5235114402Sruconst char *vline_node::type()
5236114402Sru{
5237114402Sru  return "vline_node";
5238114402Sru}
5239114402Sru
5240114402Sruint vline_node::force_tprint()
5241114402Sru{
5242114402Sru  return 0;
5243114402Sru}
5244114402Sru
5245151497Sruint vline_node::is_tag()
5246151497Sru{
5247151497Sru  return 0;
5248151497Sru}
5249151497Sru
5250114402Sruint dummy_node::same(node * /*nd*/)
5251114402Sru{
5252114402Sru  return 1;
5253114402Sru}
5254114402Sru
5255114402Sruconst char *dummy_node::type()
5256114402Sru{
5257114402Sru  return "dummy_node";
5258114402Sru}
5259114402Sru
5260114402Sruint dummy_node::force_tprint()
5261114402Sru{
5262114402Sru  return 0;
5263114402Sru}
5264114402Sru
5265151497Sruint dummy_node::is_tag()
5266151497Sru{
5267151497Sru  return 0;
5268151497Sru}
5269151497Sru
5270114402Sruint transparent_dummy_node::same(node * /*nd*/)
5271114402Sru{
5272114402Sru  return 1;
5273114402Sru}
5274114402Sru
5275114402Sruconst char *transparent_dummy_node::type()
5276114402Sru{
5277114402Sru  return "transparent_dummy_node";
5278114402Sru}
5279114402Sru
5280114402Sruint transparent_dummy_node::force_tprint()
5281114402Sru{
5282114402Sru  return 0;
5283114402Sru}
5284114402Sru
5285151497Sruint transparent_dummy_node::is_tag()
5286151497Sru{
5287151497Sru  return 0;
5288151497Sru}
5289151497Sru
5290114402Sruint transparent_dummy_node::ends_sentence()
5291114402Sru{
5292114402Sru  return 2;
5293114402Sru}
5294114402Sru
5295114402Sruint zero_width_node::same(node *nd)
5296114402Sru{
5297114402Sru  return same_node_list(n, ((zero_width_node *)nd)->n);
5298114402Sru}
5299114402Sru
5300114402Sruconst char *zero_width_node::type()
5301114402Sru{
5302114402Sru  return "zero_width_node";
5303114402Sru}
5304114402Sru
5305114402Sruint zero_width_node::force_tprint()
5306114402Sru{
5307114402Sru  return 0;
5308114402Sru}
5309114402Sru
5310151497Sruint zero_width_node::is_tag()
5311151497Sru{
5312151497Sru  return 0;
5313151497Sru}
5314151497Sru
5315114402Sruint italic_corrected_node::same(node *nd)
5316114402Sru{
5317114402Sru  return (x == ((italic_corrected_node *)nd)->x
5318114402Sru	  && same_node(n, ((italic_corrected_node *)nd)->n));
5319114402Sru}
5320114402Sru
5321114402Sruconst char *italic_corrected_node::type()
5322114402Sru{
5323114402Sru  return "italic_corrected_node";
5324114402Sru}
5325114402Sru
5326114402Sruint italic_corrected_node::force_tprint()
5327114402Sru{
5328114402Sru  return 0;
5329114402Sru}
5330114402Sru
5331151497Sruint italic_corrected_node::is_tag()
5332114402Sru{
5333151497Sru  return 0;
5334114402Sru}
5335114402Sru
5336151497Sruleft_italic_corrected_node::left_italic_corrected_node(node *xx)
5337151497Sru: node(xx), n(0)
5338151497Sru{
5339151497Sru}
5340151497Sru
5341151497Sruleft_italic_corrected_node::left_italic_corrected_node(statem *s, int pop,
5342151497Sru						       node *xx)
5343151497Sru: node(xx, s, pop), n(0)
5344151497Sru{
5345151497Sru}
5346151497Sru
5347114402Sruleft_italic_corrected_node::~left_italic_corrected_node()
5348114402Sru{
5349114402Sru  delete n;
5350114402Sru}
5351114402Sru
5352114402Srunode *left_italic_corrected_node::merge_glyph_node(glyph_node *gn)
5353114402Sru{
5354114402Sru  if (n == 0) {
5355114402Sru    hunits lic = gn->left_italic_correction();
5356114402Sru    if (!lic.is_zero()) {
5357114402Sru      x = lic;
5358114402Sru      n = gn;
5359114402Sru      return this;
5360114402Sru    }
5361114402Sru  }
5362114402Sru  else {
5363114402Sru    node *nd = n->merge_glyph_node(gn);
5364114402Sru    if (nd) {
5365114402Sru      n = nd;
5366114402Sru      x = n->left_italic_correction();
5367114402Sru      return this;
5368114402Sru    }
5369114402Sru  }
5370114402Sru  return 0;
5371114402Sru}
5372114402Sru
5373114402Srunode *left_italic_corrected_node::copy()
5374114402Sru{
5375151497Sru  left_italic_corrected_node *nd =
5376151497Sru    new left_italic_corrected_node(state, div_nest_level);
5377114402Sru  if (n) {
5378114402Sru    nd->n = n->copy();
5379114402Sru    nd->x = x;
5380114402Sru  }
5381114402Sru  return nd;
5382114402Sru}
5383114402Sru
5384114402Sruvoid left_italic_corrected_node::tprint(troff_output_file *out)
5385114402Sru{
5386114402Sru  if (n) {
5387114402Sru    out->right(x);
5388114402Sru    n->tprint(out);
5389114402Sru  }
5390114402Sru}
5391114402Sru
5392114402Sruconst char *left_italic_corrected_node::type()
5393114402Sru{
5394114402Sru  return "left_italic_corrected_node";
5395114402Sru}
5396114402Sru
5397114402Sruint left_italic_corrected_node::force_tprint()
5398114402Sru{
5399114402Sru  return 0;
5400114402Sru}
5401114402Sru
5402151497Sruint left_italic_corrected_node::is_tag()
5403151497Sru{
5404151497Sru  return 0;
5405151497Sru}
5406151497Sru
5407114402Sruint left_italic_corrected_node::same(node *nd)
5408114402Sru{
5409114402Sru  return (x == ((left_italic_corrected_node *)nd)->x
5410114402Sru	  && same_node(n, ((left_italic_corrected_node *)nd)->n));
5411114402Sru}
5412114402Sru
5413114402Sruvoid left_italic_corrected_node::ascii_print(ascii_output_file *out)
5414114402Sru{
5415114402Sru  if (n)
5416114402Sru    n->ascii_print(out);
5417114402Sru}
5418114402Sru
5419114402Sruhunits left_italic_corrected_node::width()
5420114402Sru{
5421114402Sru  return n ? n->width() + x : H0;
5422114402Sru}
5423114402Sru
5424151497Sruvoid left_italic_corrected_node::vertical_extent(vunits *minimum,
5425151497Sru						 vunits *maximum)
5426114402Sru{
5427114402Sru  if (n)
5428151497Sru    n->vertical_extent(minimum, maximum);
5429114402Sru  else
5430151497Sru    node::vertical_extent(minimum, maximum);
5431114402Sru}
5432114402Sru
5433114402Sruhunits left_italic_corrected_node::skew()
5434114402Sru{
5435114402Sru  return n ? n->skew() + x/2 : H0;
5436114402Sru}
5437114402Sru
5438114402Sruhunits left_italic_corrected_node::subscript_correction()
5439114402Sru{
5440114402Sru  return n ? n->subscript_correction() : H0;
5441114402Sru}
5442114402Sru
5443114402Sruhunits left_italic_corrected_node::italic_correction()
5444114402Sru{
5445114402Sru  return n ? n->italic_correction() : H0;
5446114402Sru}
5447114402Sru
5448114402Sruint left_italic_corrected_node::ends_sentence()
5449114402Sru{
5450114402Sru  return n ? n->ends_sentence() : 0;
5451114402Sru}
5452114402Sru
5453114402Sruint left_italic_corrected_node::overlaps_horizontally()
5454114402Sru{
5455114402Sru  return n ? n->overlaps_horizontally() : 0;
5456114402Sru}
5457114402Sru
5458114402Sruint left_italic_corrected_node::overlaps_vertically()
5459114402Sru{
5460114402Sru  return n ? n->overlaps_vertically() : 0;
5461114402Sru}
5462114402Sru
5463114402Srunode *left_italic_corrected_node::last_char_node()
5464114402Sru{
5465114402Sru  return n ? n->last_char_node() : 0;
5466114402Sru}
5467114402Sru
5468114402Srutfont *left_italic_corrected_node::get_tfont()
5469114402Sru{
5470114402Sru  return n ? n->get_tfont() : 0;
5471114402Sru}
5472114402Sru
5473114402Sruhyphenation_type left_italic_corrected_node::get_hyphenation_type()
5474114402Sru{
5475114402Sru  if (n)
5476114402Sru    return n->get_hyphenation_type();
5477114402Sru  else
5478114402Sru    return HYPHEN_MIDDLE;
5479114402Sru}
5480114402Sru
5481114402Sruhyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail,
5482114402Sru							 int *count)
5483114402Sru{
5484114402Sru  return n ? n->get_hyphen_list(tail, count) : tail;
5485114402Sru}
5486114402Sru
5487114402Srunode *left_italic_corrected_node::add_self(node *nd, hyphen_list **p)
5488114402Sru{
5489114402Sru  if (n) {
5490151497Sru    nd = new left_italic_corrected_node(state, div_nest_level, nd);
5491114402Sru    nd = n->add_self(nd, p);
5492114402Sru    n = 0;
5493114402Sru    delete this;
5494114402Sru  }
5495114402Sru  return nd;
5496114402Sru}
5497114402Sru
5498114402Sruint left_italic_corrected_node::character_type()
5499114402Sru{
5500114402Sru  return n ? n->character_type() : 0;
5501114402Sru}
5502114402Sru
5503114402Sruint overstrike_node::same(node *nd)
5504114402Sru{
5505114402Sru  return same_node_list(list, ((overstrike_node *)nd)->list);
5506114402Sru}
5507114402Sru
5508114402Sruconst char *overstrike_node::type()
5509114402Sru{
5510114402Sru  return "overstrike_node";
5511114402Sru}
5512114402Sru
5513114402Sruint overstrike_node::force_tprint()
5514114402Sru{
5515114402Sru  return 0;
5516114402Sru}
5517114402Sru
5518151497Sruint overstrike_node::is_tag()
5519151497Sru{
5520151497Sru  return 0;
5521151497Sru}
5522151497Sru
5523114402Srunode *overstrike_node::add_self(node *n, hyphen_list **p)
5524114402Sru{
5525114402Sru  next = n;
5526114402Sru  hyphen_list *pp = *p;
5527114402Sru  *p = (*p)->next;
5528114402Sru  delete pp;
5529114402Sru  return this;
5530114402Sru}
5531114402Sru
5532114402Sruhyphen_list *overstrike_node::get_hyphen_list(hyphen_list *tail, int *)
5533114402Sru{
5534114402Sru  return new hyphen_list(0, tail);
5535114402Sru}
5536114402Sru
5537114402Sruint bracket_node::same(node *nd)
5538114402Sru{
5539114402Sru  return same_node_list(list, ((bracket_node *)nd)->list);
5540114402Sru}
5541114402Sru
5542114402Sruconst char *bracket_node::type()
5543114402Sru{
5544114402Sru  return "bracket_node";
5545114402Sru}
5546114402Sru
5547114402Sruint bracket_node::force_tprint()
5548114402Sru{
5549114402Sru  return 0;
5550114402Sru}
5551114402Sru
5552151497Sruint bracket_node::is_tag()
5553151497Sru{
5554151497Sru  return 0;
5555151497Sru}
5556151497Sru
5557114402Sruint composite_node::same(node *nd)
5558114402Sru{
5559114402Sru  return ci == ((composite_node *)nd)->ci
5560114402Sru    && same_node_list(n, ((composite_node *)nd)->n);
5561114402Sru}
5562114402Sru
5563114402Sruconst char *composite_node::type()
5564114402Sru{
5565114402Sru  return "composite_node";
5566114402Sru}
5567114402Sru
5568114402Sruint composite_node::force_tprint()
5569114402Sru{
5570114402Sru  return 0;
5571114402Sru}
5572114402Sru
5573151497Sruint composite_node::is_tag()
5574151497Sru{
5575151497Sru  return 0;
5576151497Sru}
5577151497Sru
5578114402Sruint glyph_node::same(node *nd)
5579114402Sru{
5580114402Sru  return ci == ((glyph_node *)nd)->ci
5581114402Sru	 && tf == ((glyph_node *)nd)->tf
5582114402Sru	 && gcol == ((glyph_node *)nd)->gcol
5583114402Sru	 && fcol == ((glyph_node *)nd)->fcol;
5584114402Sru}
5585114402Sru
5586114402Sruconst char *glyph_node::type()
5587114402Sru{
5588114402Sru  return "glyph_node";
5589114402Sru}
5590114402Sru
5591114402Sruint glyph_node::force_tprint()
5592114402Sru{
5593114402Sru  return 0;
5594114402Sru}
5595114402Sru
5596151497Sruint glyph_node::is_tag()
5597151497Sru{
5598151497Sru  return 0;
5599151497Sru}
5600151497Sru
5601114402Sruint ligature_node::same(node *nd)
5602114402Sru{
5603114402Sru  return (same_node(n1, ((ligature_node *)nd)->n1)
5604114402Sru	  && same_node(n2, ((ligature_node *)nd)->n2)
5605114402Sru	  && glyph_node::same(nd));
5606114402Sru}
5607114402Sru
5608114402Sruconst char *ligature_node::type()
5609114402Sru{
5610114402Sru  return "ligature_node";
5611114402Sru}
5612114402Sru
5613114402Sruint ligature_node::force_tprint()
5614114402Sru{
5615114402Sru  return 0;
5616114402Sru}
5617114402Sru
5618151497Sruint ligature_node::is_tag()
5619151497Sru{
5620151497Sru  return 0;
5621151497Sru}
5622151497Sru
5623114402Sruint kern_pair_node::same(node *nd)
5624114402Sru{
5625114402Sru  return (amount == ((kern_pair_node *)nd)->amount
5626114402Sru	  && same_node(n1, ((kern_pair_node *)nd)->n1)
5627114402Sru	  && same_node(n2, ((kern_pair_node *)nd)->n2));
5628114402Sru}
5629114402Sru
5630114402Sruconst char *kern_pair_node::type()
5631114402Sru{
5632114402Sru  return "kern_pair_node";
5633114402Sru}
5634114402Sru
5635114402Sruint kern_pair_node::force_tprint()
5636114402Sru{
5637114402Sru  return 0;
5638114402Sru}
5639114402Sru
5640151497Sruint kern_pair_node::is_tag()
5641151497Sru{
5642151497Sru  return 0;
5643151497Sru}
5644151497Sru
5645114402Sruint dbreak_node::same(node *nd)
5646114402Sru{
5647114402Sru  return (same_node_list(none, ((dbreak_node *)nd)->none)
5648114402Sru	  && same_node_list(pre, ((dbreak_node *)nd)->pre)
5649114402Sru	  && same_node_list(post, ((dbreak_node *)nd)->post));
5650114402Sru}
5651114402Sru
5652114402Sruconst char *dbreak_node::type()
5653114402Sru{
5654114402Sru  return "dbreak_node";
5655114402Sru}
5656114402Sru
5657114402Sruint dbreak_node::force_tprint()
5658114402Sru{
5659114402Sru  return 0;
5660114402Sru}
5661114402Sru
5662151497Sruint dbreak_node::is_tag()
5663151497Sru{
5664151497Sru  return 0;
5665151497Sru}
5666151497Sru
5667114402Sruint break_char_node::same(node *nd)
5668114402Sru{
5669114402Sru  return break_code == ((break_char_node *)nd)->break_code
5670114402Sru	 && col == ((break_char_node *)nd)->col
5671114402Sru	 && same_node(ch, ((break_char_node *)nd)->ch);
5672114402Sru}
5673114402Sru
5674114402Sruconst char *break_char_node::type()
5675114402Sru{
5676114402Sru  return "break_char_node";
5677114402Sru}
5678114402Sru
5679114402Sruint break_char_node::force_tprint()
5680114402Sru{
5681114402Sru  return 0;
5682114402Sru}
5683114402Sru
5684151497Sruint break_char_node::is_tag()
5685151497Sru{
5686151497Sru  return 0;
5687151497Sru}
5688151497Sru
5689114402Sruint line_start_node::same(node * /*nd*/)
5690114402Sru{
5691114402Sru  return 1;
5692114402Sru}
5693114402Sru
5694114402Sruconst char *line_start_node::type()
5695114402Sru{
5696114402Sru  return "line_start_node";
5697114402Sru}
5698114402Sru
5699114402Sruint line_start_node::force_tprint()
5700114402Sru{
5701114402Sru  return 0;
5702114402Sru}
5703114402Sru
5704151497Sruint line_start_node::is_tag()
5705151497Sru{
5706151497Sru  return 0;
5707151497Sru}
5708151497Sru
5709114402Sruint space_node::same(node *nd)
5710114402Sru{
5711114402Sru  return n == ((space_node *)nd)->n
5712114402Sru	      && set == ((space_node *)nd)->set
5713114402Sru	      && col == ((space_node *)nd)->col;
5714114402Sru}
5715114402Sru
5716114402Sruconst char *space_node::type()
5717114402Sru{
5718114402Sru  return "space_node";
5719114402Sru}
5720114402Sru
5721114402Sruint word_space_node::same(node *nd)
5722114402Sru{
5723114402Sru  return n == ((word_space_node *)nd)->n
5724114402Sru	 && set == ((word_space_node *)nd)->set
5725114402Sru	 && col == ((word_space_node *)nd)->col;
5726114402Sru}
5727114402Sru
5728114402Sruconst char *word_space_node::type()
5729114402Sru{
5730114402Sru  return "word_space_node";
5731114402Sru}
5732114402Sru
5733114402Sruint word_space_node::force_tprint()
5734114402Sru{
5735114402Sru  return 0;
5736114402Sru}
5737114402Sru
5738151497Sruint word_space_node::is_tag()
5739151497Sru{
5740151497Sru  return 0;
5741151497Sru}
5742151497Sru
5743114402Sruvoid unbreakable_space_node::tprint(troff_output_file *out)
5744114402Sru{
5745114402Sru  out->fill_color(col);
5746114402Sru  if (is_html) {
5747114402Sru    // we emit the space width as a negative glyph index
5748114402Sru    out->flush_tbuf();
5749114402Sru    out->do_motion();
5750114402Sru    out->put('N');
5751114402Sru    out->put(-n.to_units());
5752114402Sru    out->put('\n');
5753114402Sru  }
5754114402Sru  out->right(n);
5755114402Sru}
5756114402Sru
5757114402Sruint unbreakable_space_node::same(node *nd)
5758114402Sru{
5759114402Sru  return n == ((unbreakable_space_node *)nd)->n
5760114402Sru	 && set == ((unbreakable_space_node *)nd)->set
5761114402Sru	 && col == ((unbreakable_space_node *)nd)->col;
5762114402Sru}
5763114402Sru
5764114402Sruconst char *unbreakable_space_node::type()
5765114402Sru{
5766114402Sru  return "unbreakable_space_node";
5767114402Sru}
5768114402Sru
5769151497Srunode *unbreakable_space_node::add_self(node *nd, hyphen_list **p)
5770114402Sru{
5771151497Sru  next = nd;
5772114402Sru  hyphen_list *pp = *p;
5773114402Sru  *p = (*p)->next;
5774114402Sru  delete pp;
5775114402Sru  return this;
5776114402Sru}
5777114402Sru
5778114402Sruhyphen_list *unbreakable_space_node::get_hyphen_list(hyphen_list *tail, int *)
5779114402Sru{
5780114402Sru  return new hyphen_list(0, tail);
5781114402Sru}
5782114402Sru
5783114402Sruint diverted_space_node::same(node *nd)
5784114402Sru{
5785114402Sru  return n == ((diverted_space_node *)nd)->n;
5786114402Sru}
5787114402Sru
5788114402Sruconst char *diverted_space_node::type()
5789114402Sru{
5790114402Sru  return "diverted_space_node";
5791114402Sru}
5792114402Sru
5793114402Sruint diverted_space_node::force_tprint()
5794114402Sru{
5795114402Sru  return 0;
5796114402Sru}
5797114402Sru
5798151497Sruint diverted_space_node::is_tag()
5799151497Sru{
5800151497Sru  return 0;
5801151497Sru}
5802151497Sru
5803114402Sruint diverted_copy_file_node::same(node *nd)
5804114402Sru{
5805114402Sru  return filename == ((diverted_copy_file_node *)nd)->filename;
5806114402Sru}
5807114402Sru
5808114402Sruconst char *diverted_copy_file_node::type()
5809114402Sru{
5810114402Sru  return "diverted_copy_file_node";
5811114402Sru}
5812114402Sru
5813114402Sruint diverted_copy_file_node::force_tprint()
5814114402Sru{
5815114402Sru  return 0;
5816114402Sru}
5817114402Sru
5818151497Sruint diverted_copy_file_node::is_tag()
5819151497Sru{
5820151497Sru  return 0;
5821151497Sru}
5822151497Sru
5823114402Sru// Grow the font_table so that its size is > n.
5824114402Sru
5825114402Srustatic void grow_font_table(int n)
5826114402Sru{
5827114402Sru  assert(n >= font_table_size);
5828114402Sru  font_info **old_font_table = font_table;
5829114402Sru  int old_font_table_size = font_table_size;
5830114402Sru  font_table_size = font_table_size ? (font_table_size*3)/2 : 10;
5831114402Sru  if (font_table_size <= n)
5832114402Sru    font_table_size = n + 10;
5833114402Sru  font_table = new font_info *[font_table_size];
5834114402Sru  if (old_font_table_size)
5835114402Sru    memcpy(font_table, old_font_table,
5836114402Sru	   old_font_table_size*sizeof(font_info *));
5837114402Sru  a_delete old_font_table;
5838114402Sru  for (int i = old_font_table_size; i < font_table_size; i++)
5839114402Sru    font_table[i] = 0;
5840114402Sru}
5841114402Sru
5842114402Srudictionary font_translation_dictionary(17);
5843114402Sru
5844114402Srustatic symbol get_font_translation(symbol nm)
5845114402Sru{
5846114402Sru  void *p = font_translation_dictionary.lookup(nm);
5847114402Sru  return p ? symbol((char *)p) : nm;
5848114402Sru}
5849114402Sru
5850114402Srudictionary font_dictionary(50);
5851114402Sru
5852151497Srustatic int mount_font_no_translate(int n, symbol name, symbol external_name,
5853151497Sru				   int check_only = 0)
5854114402Sru{
5855114402Sru  assert(n >= 0);
5856114402Sru  // We store the address of this char in font_dictionary to indicate
5857114402Sru  // that we've previously tried to mount the font and failed.
5858114402Sru  static char a_char;
5859114402Sru  font *fm = 0;
5860114402Sru  void *p = font_dictionary.lookup(external_name);
5861114402Sru  if (p == 0) {
5862114402Sru    int not_found;
5863151497Sru    fm = font::load_font(external_name.contents(), &not_found, check_only);
5864151497Sru    if (check_only)
5865151497Sru      return fm != 0;
5866114402Sru    if (!fm) {
5867114402Sru      if (not_found)
5868114402Sru	warning(WARN_FONT, "can't find font `%1'", external_name.contents());
5869114402Sru      (void)font_dictionary.lookup(external_name, &a_char);
5870114402Sru      return 0;
5871114402Sru    }
5872114402Sru    (void)font_dictionary.lookup(name, fm);
5873114402Sru  }
5874114402Sru  else if (p == &a_char) {
5875114402Sru#if 0
5876114402Sru    error("invalid font `%1'", external_name.contents());
5877114402Sru#endif
5878114402Sru    return 0;
5879114402Sru  }
5880114402Sru  else
5881114402Sru    fm = (font*)p;
5882151497Sru  if (check_only)
5883151497Sru    return 1;
5884114402Sru  if (n >= font_table_size) {
5885114402Sru    if (n - font_table_size > 1000) {
5886114402Sru      error("font position too much larger than first unused position");
5887114402Sru      return 0;
5888114402Sru    }
5889114402Sru    grow_font_table(n);
5890114402Sru  }
5891114402Sru  else if (font_table[n] != 0)
5892114402Sru    delete font_table[n];
5893114402Sru  font_table[n] = new font_info(name, n, external_name, fm);
5894114402Sru  font_family::invalidate_fontno(n);
5895114402Sru  return 1;
5896114402Sru}
5897114402Sru
5898114402Sruint mount_font(int n, symbol name, symbol external_name)
5899114402Sru{
5900114402Sru  assert(n >= 0);
5901114402Sru  name = get_font_translation(name);
5902114402Sru  if (external_name.is_null())
5903114402Sru    external_name = name;
5904114402Sru  else
5905114402Sru    external_name = get_font_translation(external_name);
5906114402Sru  return mount_font_no_translate(n, name, external_name);
5907114402Sru}
5908114402Sru
5909151497Sruint check_font(symbol fam, symbol name)
5910151497Sru{
5911151497Sru  if (check_style(name))
5912151497Sru    name = concat(fam, name);
5913151497Sru  return mount_font_no_translate(0, name, name, 1);
5914151497Sru}
5915151497Sru
5916151497Sruint check_style(symbol s)
5917151497Sru{
5918151497Sru  int i = symbol_fontno(s);
5919151497Sru  return i < 0 ? 0 : font_table[i]->is_style();
5920151497Sru}
5921151497Sru
5922114402Sruvoid mount_style(int n, symbol name)
5923114402Sru{
5924114402Sru  assert(n >= 0);
5925114402Sru  if (n >= font_table_size) {
5926114402Sru    if (n - font_table_size > 1000) {
5927114402Sru      error("font position too much larger than first unused position");
5928114402Sru      return;
5929114402Sru    }
5930114402Sru    grow_font_table(n);
5931114402Sru  }
5932114402Sru  else if (font_table[n] != 0)
5933114402Sru    delete font_table[n];
5934114402Sru  font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0);
5935114402Sru  font_family::invalidate_fontno(n);
5936114402Sru}
5937114402Sru
5938114402Sru/* global functions */
5939114402Sru
5940114402Sruvoid font_translate()
5941114402Sru{
5942114402Sru  symbol from = get_name(1);
5943114402Sru  if (!from.is_null()) {
5944114402Sru    symbol to = get_name();
5945114402Sru    if (to.is_null() || from == to)
5946114402Sru      font_translation_dictionary.remove(from);
5947114402Sru    else
5948114402Sru      (void)font_translation_dictionary.lookup(from, (void *)to.contents());
5949114402Sru  }
5950114402Sru  skip_line();
5951114402Sru}
5952114402Sru
5953114402Sruvoid font_position()
5954114402Sru{
5955114402Sru  int n;
5956114402Sru  if (get_integer(&n)) {
5957114402Sru    if (n < 0)
5958114402Sru      error("negative font position");
5959114402Sru    else {
5960114402Sru      symbol internal_name = get_name(1);
5961114402Sru      if (!internal_name.is_null()) {
5962114402Sru	symbol external_name = get_long_name();
5963114402Sru	mount_font(n, internal_name, external_name); // ignore error
5964114402Sru      }
5965114402Sru    }
5966114402Sru  }
5967114402Sru  skip_line();
5968114402Sru}
5969114402Sru
5970114402Srufont_family::font_family(symbol s)
5971114402Sru: map_size(10), nm(s)
5972114402Sru{
5973114402Sru  map = new int[map_size];
5974114402Sru  for (int i = 0; i < map_size; i++)
5975114402Sru    map[i] = -1;
5976114402Sru}
5977114402Sru
5978114402Srufont_family::~font_family()
5979114402Sru{
5980114402Sru  a_delete map;
5981114402Sru}
5982114402Sru
5983114402Sruint font_family::make_definite(int i)
5984114402Sru{
5985114402Sru  if (i >= 0) {
5986114402Sru    if (i < map_size && map[i] >= 0)
5987114402Sru      return map[i];
5988114402Sru    else {
5989114402Sru      if (i < font_table_size && font_table[i] != 0) {
5990114402Sru	if (i >= map_size) {
5991114402Sru	  int old_map_size = map_size;
5992114402Sru	  int *old_map = map;
5993114402Sru	  map_size *= 3;
5994114402Sru	  map_size /= 2;
5995114402Sru	  if (i >= map_size)
5996114402Sru	    map_size = i + 10;
5997114402Sru	  map = new int[map_size];
5998114402Sru	  memcpy(map, old_map, old_map_size*sizeof(int));
5999114402Sru	  a_delete old_map;
6000114402Sru	  for (int j = old_map_size; j < map_size; j++)
6001114402Sru	    map[j] = -1;
6002114402Sru	}
6003114402Sru	if (font_table[i]->is_style()) {
6004114402Sru	  symbol sty = font_table[i]->get_name();
6005114402Sru	  symbol f = concat(nm, sty);
6006114402Sru	  int n;
6007114402Sru	  // don't use symbol_fontno, because that might return a style
6008114402Sru	  // and because we don't want to translate the name
6009114402Sru	  for (n = 0; n < font_table_size; n++)
6010114402Sru	    if (font_table[n] != 0 && font_table[n]->is_named(f)
6011114402Sru		&& !font_table[n]->is_style())
6012114402Sru	      break;
6013114402Sru	  if (n >= font_table_size) {
6014114402Sru	    n = next_available_font_position();
6015114402Sru	    if (!mount_font_no_translate(n, f, f))
6016114402Sru	      return -1;
6017114402Sru	  }
6018114402Sru	  return map[i] = n;
6019114402Sru	}
6020114402Sru	else
6021114402Sru	  return map[i] = i;
6022114402Sru      }
6023114402Sru      else
6024114402Sru	return -1;
6025114402Sru    }
6026114402Sru  }
6027114402Sru  else
6028114402Sru    return -1;
6029114402Sru}
6030114402Sru
6031114402Srudictionary family_dictionary(5);
6032114402Sru
6033114402Srufont_family *lookup_family(symbol nm)
6034114402Sru{
6035114402Sru  font_family *f = (font_family *)family_dictionary.lookup(nm);
6036114402Sru  if (!f) {
6037114402Sru    f = new font_family(nm);
6038114402Sru    (void)family_dictionary.lookup(nm, f);
6039114402Sru  }
6040114402Sru  return f;
6041114402Sru}
6042114402Sru
6043114402Sruvoid font_family::invalidate_fontno(int n)
6044114402Sru{
6045114402Sru  assert(n >= 0 && n < font_table_size);
6046114402Sru  dictionary_iterator iter(family_dictionary);
6047151497Sru  symbol nam;
6048114402Sru  font_family *fam;
6049151497Sru  while (iter.get(&nam, (void **)&fam)) {
6050151497Sru    int mapsize = fam->map_size;
6051151497Sru    if (n < mapsize)
6052114402Sru      fam->map[n] = -1;
6053151497Sru    for (int i = 0; i < mapsize; i++)
6054114402Sru      if (fam->map[i] == n)
6055114402Sru	fam->map[i] = -1;
6056114402Sru  }
6057114402Sru}
6058114402Sru
6059114402Sruvoid style()
6060114402Sru{
6061114402Sru  int n;
6062114402Sru  if (get_integer(&n)) {
6063114402Sru    if (n < 0)
6064114402Sru      error("negative font position");
6065114402Sru    else {
6066114402Sru      symbol internal_name = get_name(1);
6067114402Sru      if (!internal_name.is_null())
6068114402Sru	mount_style(n, internal_name);
6069114402Sru    }
6070114402Sru  }
6071114402Sru  skip_line();
6072114402Sru}
6073114402Sru
6074114402Srustatic int get_fontno()
6075114402Sru{
6076114402Sru  int n;
6077114402Sru  tok.skip();
6078114402Sru  if (tok.delimiter()) {
6079114402Sru    symbol s = get_name(1);
6080114402Sru    if (!s.is_null()) {
6081114402Sru      n = symbol_fontno(s);
6082114402Sru      if (n < 0) {
6083114402Sru	n = next_available_font_position();
6084114402Sru	if (!mount_font(n, s))
6085114402Sru	  return -1;
6086114402Sru      }
6087114402Sru      return curenv->get_family()->make_definite(n);
6088114402Sru    }
6089114402Sru  }
6090114402Sru  else if (get_integer(&n)) {
6091114402Sru    if (n < 0 || n >= font_table_size || font_table[n] == 0)
6092114402Sru      error("bad font number");
6093114402Sru    else
6094114402Sru      return curenv->get_family()->make_definite(n);
6095114402Sru  }
6096114402Sru  return -1;
6097114402Sru}
6098114402Sru
6099114402Srustatic int underline_fontno = 2;
6100114402Sru
6101114402Sruvoid underline_font()
6102114402Sru{
6103114402Sru  int n = get_fontno();
6104114402Sru  if (n >= 0)
6105114402Sru    underline_fontno = n;
6106114402Sru  skip_line();
6107114402Sru}
6108114402Sru
6109114402Sruint get_underline_fontno()
6110114402Sru{
6111114402Sru  return underline_fontno;
6112114402Sru}
6113114402Sru
6114114402Sruvoid define_font_special_character()
6115114402Sru{
6116114402Sru  int n = get_fontno();
6117114402Sru  if (n < 0) {
6118114402Sru    skip_line();
6119114402Sru    return;
6120114402Sru  }
6121114402Sru  symbol f = font_table[n]->get_name();
6122114402Sru  do_define_character(CHAR_FONT_SPECIAL, f.contents());
6123114402Sru}
6124114402Sru
6125114402Sruvoid remove_font_special_character()
6126114402Sru{
6127114402Sru  int n = get_fontno();
6128114402Sru  if (n < 0) {
6129114402Sru    skip_line();
6130114402Sru    return;
6131114402Sru  }
6132114402Sru  symbol f = font_table[n]->get_name();
6133114402Sru  while (!tok.newline() && !tok.eof()) {
6134114402Sru    if (!tok.space() && !tok.tab()) {
6135114402Sru      charinfo *s = tok.get_char(1);
6136114402Sru      string gl(f.contents());
6137114402Sru      gl += ' ';
6138114402Sru      gl += s->nm.contents();
6139114402Sru      gl += '\0';
6140114402Sru      charinfo *ci = get_charinfo(symbol(gl.contents()));
6141114402Sru      if (!ci)
6142114402Sru	break;
6143114402Sru      macro *m = ci->set_macro(0);
6144114402Sru      if (m)
6145114402Sru	delete m;
6146114402Sru    }
6147114402Sru    tok.next();
6148114402Sru  }
6149114402Sru  skip_line();
6150114402Sru}
6151114402Sru
6152114402Srustatic void read_special_fonts(special_font_list **sp)
6153114402Sru{
6154114402Sru  special_font_list *s = *sp;
6155114402Sru  *sp = 0;
6156114402Sru  while (s != 0) {
6157114402Sru    special_font_list *tem = s;
6158114402Sru    s = s->next;
6159114402Sru    delete tem;
6160114402Sru  }
6161114402Sru  special_font_list **p = sp;
6162114402Sru  while (has_arg()) {
6163114402Sru    int i = get_fontno();
6164114402Sru    if (i >= 0) {
6165114402Sru      special_font_list *tem = new special_font_list;
6166114402Sru      tem->n = i;
6167114402Sru      tem->next = 0;
6168114402Sru      *p = tem;
6169114402Sru      p = &(tem->next);
6170114402Sru    }
6171114402Sru  }
6172114402Sru}
6173114402Sru
6174114402Sruvoid font_special_request()
6175114402Sru{
6176114402Sru  int n = get_fontno();
6177114402Sru  if (n >= 0)
6178114402Sru    read_special_fonts(&font_table[n]->sf);
6179114402Sru  skip_line();
6180114402Sru}
6181114402Sru
6182114402Sruvoid special_request()
6183114402Sru{
6184114402Sru  read_special_fonts(&global_special_fonts);
6185114402Sru  skip_line();
6186114402Sru}
6187114402Sru
6188114402Sruint next_available_font_position()
6189114402Sru{
6190114402Sru  int i;
6191114402Sru  for (i = 1; i < font_table_size && font_table[i] != 0; i++)
6192114402Sru    ;
6193114402Sru  return i;
6194114402Sru}
6195114402Sru
6196114402Sruint symbol_fontno(symbol s)
6197114402Sru{
6198114402Sru  s = get_font_translation(s);
6199114402Sru  for (int i = 0; i < font_table_size; i++)
6200114402Sru    if (font_table[i] != 0 && font_table[i]->is_named(s))
6201114402Sru      return i;
6202114402Sru  return -1;
6203114402Sru}
6204114402Sru
6205114402Sruint is_good_fontno(int n)
6206114402Sru{
6207114402Sru  return n >= 0 && n < font_table_size && font_table[n] != 0;
6208114402Sru}
6209114402Sru
6210114402Sruint get_bold_fontno(int n)
6211114402Sru{
6212114402Sru  if (n >= 0 && n < font_table_size && font_table[n] != 0) {
6213114402Sru    hunits offset;
6214114402Sru    if (font_table[n]->get_bold(&offset))
6215114402Sru      return offset.to_units() + 1;
6216114402Sru    else
6217114402Sru      return 0;
6218114402Sru  }
6219114402Sru  else
6220114402Sru    return 0;
6221114402Sru}
6222114402Sru
6223114402Sruhunits env_digit_width(environment *env)
6224114402Sru{
6225114402Sru  node *n = make_glyph_node(charset_table['0'], env);
6226114402Sru  if (n) {
6227114402Sru    hunits x = n->width();
6228114402Sru    delete n;
6229114402Sru    return x;
6230114402Sru  }
6231114402Sru  else
6232114402Sru    return H0;
6233114402Sru}
6234114402Sru
6235114402Sruhunits env_space_width(environment *env)
6236114402Sru{
6237114402Sru  int fn = env_definite_font(env);
6238114402Sru  font_size fs = env->get_font_size();
6239114402Sru  if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6240114402Sru    return scale(fs.to_units()/3, env->get_space_size(), 12);
6241114402Sru  else
6242114402Sru    return font_table[fn]->get_space_width(fs, env->get_space_size());
6243114402Sru}
6244114402Sru
6245114402Sruhunits env_sentence_space_width(environment *env)
6246114402Sru{
6247114402Sru  int fn = env_definite_font(env);
6248114402Sru  font_size fs = env->get_font_size();
6249114402Sru  if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6250114402Sru    return scale(fs.to_units()/3, env->get_sentence_space_size(), 12);
6251114402Sru  else
6252114402Sru    return font_table[fn]->get_space_width(fs, env->get_sentence_space_size());
6253114402Sru}
6254114402Sru
6255114402Sruhunits env_half_narrow_space_width(environment *env)
6256114402Sru{
6257114402Sru  int fn = env_definite_font(env);
6258114402Sru  font_size fs = env->get_font_size();
6259114402Sru  if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6260114402Sru    return 0;
6261114402Sru  else
6262114402Sru    return font_table[fn]->get_half_narrow_space_width(fs);
6263114402Sru}
6264114402Sru
6265114402Sruhunits env_narrow_space_width(environment *env)
6266114402Sru{
6267114402Sru  int fn = env_definite_font(env);
6268114402Sru  font_size fs = env->get_font_size();
6269114402Sru  if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6270114402Sru    return 0;
6271114402Sru  else
6272114402Sru    return font_table[fn]->get_narrow_space_width(fs);
6273114402Sru}
6274114402Sru
6275114402Sruvoid bold_font()
6276114402Sru{
6277114402Sru  int n = get_fontno();
6278114402Sru  if (n >= 0) {
6279114402Sru    if (has_arg()) {
6280114402Sru      if (tok.delimiter()) {
6281114402Sru	int f = get_fontno();
6282114402Sru	if (f >= 0) {
6283114402Sru	  units offset;
6284114402Sru	  if (has_arg() && get_number(&offset, 'u') && offset >= 1)
6285114402Sru	    font_table[f]->set_conditional_bold(n, hunits(offset - 1));
6286114402Sru	  else
6287114402Sru	    font_table[f]->conditional_unbold(n);
6288114402Sru	}
6289114402Sru      }
6290114402Sru      else {
6291114402Sru	units offset;
6292114402Sru	if (get_number(&offset, 'u') && offset >= 1)
6293114402Sru	  font_table[n]->set_bold(hunits(offset - 1));
6294114402Sru	else
6295114402Sru	  font_table[n]->unbold();
6296114402Sru      }
6297114402Sru    }
6298114402Sru    else
6299114402Sru      font_table[n]->unbold();
6300114402Sru  }
6301114402Sru  skip_line();
6302114402Sru}
6303114402Sru
6304114402Srutrack_kerning_function::track_kerning_function() : non_zero(0)
6305114402Sru{
6306114402Sru}
6307114402Sru
6308114402Srutrack_kerning_function::track_kerning_function(int min_s, hunits min_a,
6309114402Sru					       int max_s, hunits max_a)
6310114402Sru: non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s),
6311114402Sru  max_amount(max_a)
6312114402Sru{
6313114402Sru}
6314114402Sru
6315114402Sruint track_kerning_function::operator==(const track_kerning_function &tk)
6316114402Sru{
6317114402Sru  if (non_zero)
6318114402Sru    return (tk.non_zero
6319114402Sru	    && min_size == tk.min_size
6320114402Sru	    && min_amount == tk.min_amount
6321114402Sru	    && max_size == tk.max_size
6322114402Sru	    && max_amount == tk.max_amount);
6323114402Sru  else
6324114402Sru    return !tk.non_zero;
6325114402Sru}
6326114402Sru
6327114402Sruint track_kerning_function::operator!=(const track_kerning_function &tk)
6328114402Sru{
6329114402Sru  if (non_zero)
6330114402Sru    return (!tk.non_zero
6331114402Sru	    || min_size != tk.min_size
6332114402Sru	    || min_amount != tk.min_amount
6333114402Sru	    || max_size != tk.max_size
6334114402Sru	    || max_amount != tk.max_amount);
6335114402Sru  else
6336114402Sru    return tk.non_zero;
6337114402Sru}
6338114402Sru
6339114402Sruhunits track_kerning_function::compute(int size)
6340114402Sru{
6341114402Sru  if (non_zero) {
6342114402Sru    if (max_size <= min_size)
6343114402Sru      return min_amount;
6344114402Sru    else if (size <= min_size)
6345114402Sru      return min_amount;
6346114402Sru    else if (size >= max_size)
6347114402Sru      return max_amount;
6348114402Sru    else
6349114402Sru      return (scale(max_amount, size - min_size, max_size - min_size)
6350114402Sru	      + scale(min_amount, max_size - size, max_size - min_size));
6351114402Sru  }
6352114402Sru  else
6353114402Sru    return H0;
6354114402Sru}
6355114402Sru
6356114402Sruvoid track_kern()
6357114402Sru{
6358114402Sru  int n = get_fontno();
6359114402Sru  if (n >= 0) {
6360114402Sru    int min_s, max_s;
6361114402Sru    hunits min_a, max_a;
6362114402Sru    if (has_arg()
6363114402Sru	&& get_number(&min_s, 'z')
6364114402Sru	&& get_hunits(&min_a, 'p')
6365114402Sru	&& get_number(&max_s, 'z')
6366114402Sru	&& get_hunits(&max_a, 'p')) {
6367114402Sru      track_kerning_function tk(min_s, min_a, max_s, max_a);
6368114402Sru      font_table[n]->set_track_kern(tk);
6369114402Sru    }
6370114402Sru    else {
6371114402Sru      track_kerning_function tk;
6372114402Sru      font_table[n]->set_track_kern(tk);
6373114402Sru    }
6374114402Sru  }
6375114402Sru  skip_line();
6376114402Sru}
6377114402Sru
6378114402Sruvoid constant_space()
6379114402Sru{
6380114402Sru  int n = get_fontno();
6381114402Sru  if (n >= 0) {
6382114402Sru    int x, y;
6383114402Sru    if (!has_arg() || !get_integer(&x))
6384114402Sru      font_table[n]->set_constant_space(CONSTANT_SPACE_NONE);
6385114402Sru    else {
6386114402Sru      if (!has_arg() || !get_number(&y, 'z'))
6387114402Sru	font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x);
6388114402Sru      else
6389114402Sru	font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE,
6390114402Sru					  scale(y*x,
6391114402Sru						units_per_inch,
6392114402Sru						36*72*sizescale));
6393114402Sru    }
6394114402Sru  }
6395114402Sru  skip_line();
6396114402Sru}
6397114402Sru
6398114402Sruvoid ligature()
6399114402Sru{
6400114402Sru  int lig;
6401114402Sru  if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2)
6402114402Sru    global_ligature_mode = lig;
6403114402Sru  else
6404114402Sru    global_ligature_mode = 1;
6405114402Sru  skip_line();
6406114402Sru}
6407114402Sru
6408114402Sruvoid kern_request()
6409114402Sru{
6410114402Sru  int k;
6411114402Sru  if (has_arg() && get_integer(&k))
6412114402Sru    global_kern_mode = k != 0;
6413114402Sru  else
6414114402Sru    global_kern_mode = 1;
6415114402Sru  skip_line();
6416114402Sru}
6417114402Sru
6418114402Sruvoid set_soft_hyphen_char()
6419114402Sru{
6420114402Sru  soft_hyphen_char = get_optional_char();
6421114402Sru  if (!soft_hyphen_char)
6422114402Sru    soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
6423114402Sru  skip_line();
6424114402Sru}
6425114402Sru
6426114402Sruvoid init_output()
6427114402Sru{
6428114402Sru  if (suppress_output_flag)
6429114402Sru    the_output = new suppress_output_file;
6430114402Sru  else if (ascii_output_flag)
6431114402Sru    the_output = new ascii_output_file;
6432114402Sru  else
6433114402Sru    the_output = new troff_output_file;
6434114402Sru}
6435114402Sru
6436114402Sruclass next_available_font_position_reg : public reg {
6437114402Srupublic:
6438114402Sru  const char *get_string();
6439114402Sru};
6440114402Sru
6441114402Sruconst char *next_available_font_position_reg::get_string()
6442114402Sru{
6443114402Sru  return i_to_a(next_available_font_position());
6444114402Sru}
6445114402Sru
6446114402Sruclass printing_reg : public reg {
6447114402Srupublic:
6448114402Sru  const char *get_string();
6449114402Sru};
6450114402Sru
6451114402Sruconst char *printing_reg::get_string()
6452114402Sru{
6453114402Sru  if (the_output)
6454114402Sru    return the_output->is_printing() ? "1" : "0";
6455114402Sru  else
6456114402Sru    return "0";
6457114402Sru}
6458114402Sru
6459114402Sruvoid init_node_requests()
6460114402Sru{
6461114402Sru  init_request("bd", bold_font);
6462114402Sru  init_request("cs", constant_space);
6463114402Sru  init_request("fp", font_position);
6464114402Sru  init_request("fschar", define_font_special_character);
6465114402Sru  init_request("fspecial", font_special_request);
6466114402Sru  init_request("ftr", font_translate);
6467114402Sru  init_request("kern", kern_request);
6468114402Sru  init_request("lg", ligature);
6469114402Sru  init_request("rfschar", remove_font_special_character);
6470114402Sru  init_request("shc", set_soft_hyphen_char);
6471114402Sru  init_request("special", special_request);
6472114402Sru  init_request("sty", style);
6473114402Sru  init_request("tkf", track_kern);
6474114402Sru  init_request("uf", underline_font);
6475114402Sru  number_reg_dictionary.define(".fp", new next_available_font_position_reg);
6476114402Sru  number_reg_dictionary.define(".kern",
6477114402Sru			       new constant_int_reg(&global_kern_mode));
6478114402Sru  number_reg_dictionary.define(".lg",
6479114402Sru			       new constant_int_reg(&global_ligature_mode));
6480114402Sru  number_reg_dictionary.define(".P", new printing_reg);
6481114402Sru  soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
6482114402Sru}
6483