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