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