2 /* Copyright (C) 1989-2014 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 extern int debug_state;
28 #include "dictionary.h"
30 #include "stringclass.h"
49 #else /* not _POSIX_VERSION */
51 /* traditional Unix */
53 #define WIFEXITED(s) (((s) & 0377) == 0)
54 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
55 #define WTERMSIG(s) ((s) & 0177)
56 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
57 #define WSTOPSIG(s) (((s) >> 8) & 0377)
58 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
60 #endif /* not _POSIX_VERSION */
62 // declarations to avoid friend name injections
65 tfont *make_tfont(tfont_spec &);
69 * how many boundaries of images have been written? Useful for
74 static int suppress_start_page = 0;
78 symbol HYPHEN_SYMBOL("hy");
80 // Character used when a hyphen is inserted at a line break.
81 static charinfo *soft_hyphen_char;
83 enum constant_space_type {
85 CONSTANT_SPACE_RELATIVE,
86 CONSTANT_SPACE_ABSOLUTE
89 struct special_font_list {
91 special_font_list *next;
94 special_font_list *global_special_fonts;
95 static int global_ligature_mode = 1;
96 static int global_kern_mode = 1;
98 class track_kerning_function {
105 track_kerning_function();
106 track_kerning_function(units, hunits, units, hunits);
107 int operator==(const track_kerning_function &);
108 int operator!=(const track_kerning_function &);
109 hunits compute(int point_size);
112 // embolden fontno when this is the current font
114 struct conditional_bold {
115 conditional_bold *next;
118 conditional_bold(int, hunits, conditional_bold * = 0);
127 symbol internal_name;
128 symbol external_name;
132 track_kerning_function track_kern;
133 constant_space_type is_constant_spaced;
134 units constant_space;
135 int last_ligature_mode;
137 conditional_bold *cond_bold_list;
140 special_font_list *sf;
141 font_info(symbol, int, symbol, font *);
142 int contains(charinfo *);
143 void set_bold(hunits);
145 void set_conditional_bold(int, hunits);
146 void conditional_unbold(int);
147 void set_track_kern(track_kerning_function &);
148 void set_constant_space(constant_space_type, units = 0);
149 int is_named(symbol);
151 tfont *get_tfont(font_size, int, int, int);
152 hunits get_space_width(font_size, int);
153 hunits get_narrow_space_width(font_size);
154 hunits get_half_narrow_space_width(font_size);
155 int get_bold(hunits *);
160 friend symbol get_font_name(int, environment *);
161 friend symbol get_style_name(int);
171 char is_constant_spaced;
175 hunits track_kern; // add this to the width
176 hunits constant_space_width;
180 tfont_spec(symbol, int, font *, font_size, int, int);
181 tfont_spec(const tfont_spec &spec) { *this = spec; }
183 int operator==(const tfont_spec &);
184 friend tfont *font_info::get_tfont(font_size fs, int, int, int);
187 class tfont : public tfont_spec {
188 static tfont *tfont_list;
190 tfont *plain_version;
193 int contains(charinfo *);
194 hunits get_width(charinfo *c);
195 int get_bold(hunits *);
196 int get_constant_space(hunits *);
197 hunits get_track_kern();
199 font_size get_size();
202 charinfo *get_lig(charinfo *c1, charinfo *c2);
203 int get_kern(charinfo *c1, charinfo *c2, hunits *res);
204 int get_input_position();
205 int get_character_type(charinfo *);
208 vunits get_char_height(charinfo *);
209 vunits get_char_depth(charinfo *);
210 hunits get_char_skew(charinfo *);
211 hunits get_italic_correction(charinfo *);
212 hunits get_left_italic_correction(charinfo *);
213 hunits get_subscript_correction(charinfo *);
214 friend tfont *make_tfont(tfont_spec &);
217 inline int env_definite_font(environment *env)
219 return env->get_family()->make_definite(env->get_font());
222 /* font_info functions */
224 static font_info **font_table = 0;
225 static int font_table_size = 0;
227 font_info::font_info(symbol nm, int n, symbol enm, font *f)
228 : last_tfont(0), number(n), last_size(0),
229 internal_name(nm), external_name(enm), fm(f),
230 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1),
231 last_kern_mode(1), cond_bold_list(0), sf(0)
235 inline int font_info::contains(charinfo *ci)
237 return fm != 0 && fm->contains(ci->as_glyph());
240 inline int font_info::is_special()
242 return fm != 0 && fm->is_special();
245 inline int font_info::is_style()
250 void font_info::set_zoom(int zoom)
256 inline int font_info::get_zoom()
260 return fm->get_zoom();
263 tfont *make_tfont(tfont_spec &spec)
265 for (tfont *p = tfont::tfont_list; p; p = p->next)
268 return new tfont(spec);
271 int env_get_zoom(environment *env)
273 int fontno = env->get_family()->make_definite(env->get_font());
274 return font_table[fontno]->get_zoom();
277 // this is the current_font, fontno is where we found the character,
278 // presumably a special font
280 tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
282 if (last_tfont == 0 || fs != last_size
283 || height != last_height || slant != last_slant
284 || global_ligature_mode != last_ligature_mode
285 || global_kern_mode != last_kern_mode
286 || fontno != number) {
287 font_info *f = font_table[fontno];
288 tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
289 for (conditional_bold *p = cond_bold_list; p; p = p->next)
290 if (p->fontno == fontno) {
292 spec.bold_offset = p->offset;
295 if (!spec.is_bold && is_bold) {
297 spec.bold_offset = bold_offset;
299 spec.track_kern = track_kern.compute(fs.to_scaled_points());
300 spec.ligature_mode = global_ligature_mode;
301 spec.kern_mode = global_kern_mode;
302 switch (is_constant_spaced) {
303 case CONSTANT_SPACE_NONE:
305 case CONSTANT_SPACE_ABSOLUTE:
306 spec.is_constant_spaced = 1;
307 spec.constant_space_width = constant_space;
309 case CONSTANT_SPACE_RELATIVE:
310 spec.is_constant_spaced = 1;
311 spec.constant_space_width
312 = scale(constant_space*fs.to_scaled_points(),
319 if (fontno != number)
320 return make_tfont(spec);
321 // save font for comparison purposes
322 last_tfont = make_tfont(spec);
323 // save font related values not contained in tfont
325 last_height = height;
327 last_ligature_mode = global_ligature_mode;
328 last_kern_mode = global_kern_mode;
333 int font_info::get_bold(hunits *res)
343 void font_info::unbold()
351 void font_info::set_bold(hunits offset)
353 if (!is_bold || offset != bold_offset) {
355 bold_offset = offset;
360 void font_info::set_conditional_bold(int fontno, hunits offset)
362 for (conditional_bold *p = cond_bold_list; p; p = p->next)
363 if (p->fontno == fontno) {
364 if (offset != p->offset) {
370 cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
373 conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
374 : next(x), fontno(f), offset(h)
378 void font_info::conditional_unbold(int fontno)
380 for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
381 if ((*p)->fontno == fontno) {
382 conditional_bold *tem = *p;
390 void font_info::set_constant_space(constant_space_type type, units x)
392 if (type != is_constant_spaced
393 || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
395 is_constant_spaced = type;
400 void font_info::set_track_kern(track_kerning_function &tk)
402 if (track_kern != tk) {
408 void font_info::flush()
413 int font_info::is_named(symbol s)
415 return internal_name == s;
418 symbol font_info::get_name()
420 return internal_name;
423 symbol get_font_name(int fontno, environment *env)
425 symbol f = font_table[fontno]->get_name();
426 if (font_table[fontno]->is_style()) {
427 return concat(env->get_family()->nm, f);
432 symbol get_style_name(int fontno)
434 if (font_table[fontno]->is_style())
435 return font_table[fontno]->get_name();
440 hunits font_info::get_space_width(font_size fs, int space_sz)
442 if (is_constant_spaced == CONSTANT_SPACE_NONE)
443 return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
445 else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
446 return constant_space;
448 return scale(constant_space*fs.to_scaled_points(),
449 units_per_inch, 36*72*sizescale);
452 hunits font_info::get_narrow_space_width(font_size fs)
454 charinfo *ci = get_charinfo(symbol("|"));
455 if (fm->contains(ci->as_glyph()))
456 return hunits(fm->get_width(ci->as_glyph(), fs.to_scaled_points()));
458 return hunits(fs.to_units()/6);
461 hunits font_info::get_half_narrow_space_width(font_size fs)
463 charinfo *ci = get_charinfo(symbol("^"));
464 if (fm->contains(ci->as_glyph()))
465 return hunits(fm->get_width(ci->as_glyph(), fs.to_scaled_points()));
467 return hunits(fs.to_units()/12);
472 tfont_spec::tfont_spec(symbol nm, int n, font *f,
473 font_size s, int h, int sl)
474 : name(nm), input_position(n), fm(f), size(s),
475 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
478 if (height == size.to_scaled_points())
482 int tfont_spec::operator==(const tfont_spec &spec)
486 && input_position == spec.input_position
488 && height == spec.height
489 && slant == spec.slant
491 ? (spec.is_bold && bold_offset == spec.bold_offset)
493 && track_kern == spec.track_kern
494 && (is_constant_spaced
495 ? (spec.is_constant_spaced
496 && constant_space_width == spec.constant_space_width)
497 : !spec.is_constant_spaced)
498 && ligature_mode == spec.ligature_mode
499 && kern_mode == spec.kern_mode)
505 tfont_spec tfont_spec::plain()
507 return tfont_spec(name, input_position, fm, size, height, slant);
510 hunits tfont::get_width(charinfo *c)
512 if (is_constant_spaced)
513 return constant_space_width;
515 return (hunits(fm->get_width(c->as_glyph(), size.to_scaled_points()))
516 + track_kern + bold_offset);
518 return (hunits(fm->get_width(c->as_glyph(), size.to_scaled_points()))
522 vunits tfont::get_char_height(charinfo *c)
524 vunits v = fm->get_height(c->as_glyph(), size.to_scaled_points());
525 if (height != 0 && height != size.to_scaled_points())
526 return scale(v, height, size.to_scaled_points());
531 vunits tfont::get_char_depth(charinfo *c)
533 vunits v = fm->get_depth(c->as_glyph(), size.to_scaled_points());
534 if (height != 0 && height != size.to_scaled_points())
535 return scale(v, height, size.to_scaled_points());
540 hunits tfont::get_char_skew(charinfo *c)
542 return hunits(fm->get_skew(c->as_glyph(), size.to_scaled_points(), slant));
545 hunits tfont::get_italic_correction(charinfo *c)
547 return hunits(fm->get_italic_correction(c->as_glyph(), size.to_scaled_points()));
550 hunits tfont::get_left_italic_correction(charinfo *c)
552 return hunits(fm->get_left_italic_correction(c->as_glyph(),
553 size.to_scaled_points()));
556 hunits tfont::get_subscript_correction(charinfo *c)
558 return hunits(fm->get_subscript_correction(c->as_glyph(),
559 size.to_scaled_points()));
562 inline int tfont::get_input_position()
564 return input_position;
567 inline int tfont::contains(charinfo *ci)
569 return fm->contains(ci->as_glyph());
572 inline int tfont::get_character_type(charinfo *ci)
574 return fm->get_character_type(ci->as_glyph());
577 inline int tfont::get_bold(hunits *res)
587 inline int tfont::get_constant_space(hunits *res)
589 if (is_constant_spaced) {
590 *res = constant_space_width;
597 inline hunits tfont::get_track_kern()
602 inline tfont *tfont::get_plain()
604 return plain_version;
607 inline font_size tfont::get_size()
612 inline int tfont::get_zoom()
614 return fm->get_zoom();
617 inline symbol tfont::get_name()
622 inline int tfont::get_height()
627 inline int tfont::get_slant()
632 symbol SYMBOL_ff("ff");
633 symbol SYMBOL_fi("fi");
634 symbol SYMBOL_fl("fl");
635 symbol SYMBOL_Fi("Fi");
636 symbol SYMBOL_Fl("Fl");
638 charinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
640 if (ligature_mode == 0)
643 if (c1->get_ascii_code() == 'f') {
644 switch (c2->get_ascii_code()) {
646 if (fm->has_ligature(font::LIG_ff))
647 ci = get_charinfo(SYMBOL_ff);
650 if (fm->has_ligature(font::LIG_fi))
651 ci = get_charinfo(SYMBOL_fi);
654 if (fm->has_ligature(font::LIG_fl))
655 ci = get_charinfo(SYMBOL_fl);
659 else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
660 switch (c2->get_ascii_code()) {
662 if (fm->has_ligature(font::LIG_ffi))
663 ci = get_charinfo(SYMBOL_Fi);
666 if (fm->has_ligature(font::LIG_ffl))
667 ci = get_charinfo(SYMBOL_Fl);
671 if (ci != 0 && fm->contains(ci->as_glyph()))
676 inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
681 int n = fm->get_kern(c1->as_glyph(),
683 size.to_scaled_points());
693 tfont *tfont::tfont_list = 0;
695 tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
699 tfont_spec plain_spec = plain();
701 for (p = tfont_list; p; p = p->next)
702 if (*p == plain_spec) {
707 plain_version = new tfont(plain_spec);
712 class real_output_file : public output_file {
713 #ifndef POPEN_MISSING
716 int printing; // decision via optional page list
717 int output_on; // \O[0] or \O[1] escape calls
718 virtual void really_transparent_char(unsigned char) = 0;
719 virtual void really_print_line(hunits x, vunits y, node *n,
720 vunits before, vunits after, hunits width) = 0;
721 virtual void really_begin_page(int pageno, vunits page_length) = 0;
722 virtual void really_copy_file(hunits x, vunits y, const char *filename);
723 virtual void really_put_filename(const char *, int);
724 virtual void really_on();
725 virtual void really_off();
731 void transparent_char(unsigned char);
732 void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
733 void begin_page(int pageno, vunits page_length);
734 void put_filename(const char *, int);
739 void copy_file(hunits x, vunits y, const char *filename);
742 class suppress_output_file : public real_output_file {
744 suppress_output_file();
745 void really_transparent_char(unsigned char);
746 void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
747 void really_begin_page(int pageno, vunits page_length);
750 class ascii_output_file : public real_output_file {
753 void really_transparent_char(unsigned char);
754 void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
755 void really_begin_page(int pageno, vunits page_length);
756 void outc(unsigned char c);
757 void outs(const char *s);
760 void ascii_output_file::outc(unsigned char c)
765 void ascii_output_file::outs(const char *s)
775 class troff_output_file : public real_output_file {
784 tfont *current_tfont;
785 color *current_fill_color;
786 color *current_glyph_color;
787 int current_font_number;
788 symbol *font_position;
790 enum { TBUF_SIZE = 256 };
791 char tbuf[TBUF_SIZE];
799 void put(unsigned char c);
801 void put(unsigned int i);
802 void put(const char *s);
803 void set_font(tfont *tf);
807 ~troff_output_file();
808 void trailer(vunits page_length);
809 void put_char(charinfo *, tfont *, color *, color *);
810 void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits);
813 void moveto(hunits, vunits);
814 void start_special(tfont *, color *, color *, int = 0);
815 void start_special();
816 void special_char(unsigned char c);
819 void really_transparent_char(unsigned char c);
820 void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
821 void really_begin_page(int pageno, vunits page_length);
822 void really_copy_file(hunits x, vunits y, const char *filename);
823 void really_put_filename(const char *, int);
826 void draw(char, hvpair *, int, font_size, color *, color *);
827 void determine_line_limits (char code, hvpair *point, int npoints);
828 void check_charinfo(tfont *tf, charinfo *ci);
829 void glyph_color(color *c);
830 void fill_color(color *c);
831 int get_hpos() { return hpos; }
832 int get_vpos() { return vpos; }
833 void add_to_tag_list(string s);
834 friend void space_char_hmotion_node::tprint(troff_output_file *);
835 friend void unbreakable_space_node::tprint(troff_output_file *);
838 static void put_string(const char *s, FILE *fp)
840 for (; *s != '\0'; ++s)
844 inline void troff_output_file::put(char c)
849 inline void troff_output_file::put(unsigned char c)
854 inline void troff_output_file::put(const char *s)
859 inline void troff_output_file::put(int i)
861 put_string(i_to_a(i), fp);
864 inline void troff_output_file::put(unsigned int i)
866 put_string(ui_to_a(i), fp);
869 void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol,
881 void troff_output_file::start_special()
888 void troff_output_file::special_char(unsigned char c)
895 void troff_output_file::end_special()
900 inline void troff_output_file::moveto(hunits h, vunits v)
906 void troff_output_file::really_print_line(hunits x, vunits y, node *n,
907 vunits before, vunits after, hunits)
911 // Check whether we should push the current troff state and use
912 // the state at the start of the invocation of this diversion.
913 if (n->div_nest_level > cur_div_level && n->push_state) {
914 state.push_state(n->push_state);
915 cur_div_level = n->div_nest_level;
917 // Has the current diversion level decreased? Then we must pop the
919 while (n->div_nest_level < cur_div_level) {
921 cur_div_level = n->div_nest_level;
923 // Now check whether the state has changed.
924 if ((is_on() || n->force_tprint())
925 && (state.changed(n->state) || n->is_tag() || n->is_special)) {
930 state.flush(fp, n->state, tag_list);
931 tag_list = string("");
938 // This ensures that transparent throughput will have a more predictable
944 put(before.to_units());
946 put(after.to_units());
950 inline void troff_output_file::word_marker()
957 inline void troff_output_file::right(hunits n)
959 hpos += n.to_units();
962 inline void troff_output_file::down(vunits n)
964 vpos += n.to_units();
967 void troff_output_file::do_motion()
978 if (hpos != output_hpos) {
979 units n = hpos - output_hpos;
980 if (n > 0 && n < hpos) {
990 if (vpos != output_vpos) {
991 units n = vpos - output_vpos;
992 if (n > 0 && n < vpos) {
1008 void troff_output_file::flush_tbuf()
1024 check_output_limits(hpos, vpos);
1025 check_output_limits(hpos, vpos - current_size);
1027 for (int i = 0; i < tbuf_len; i++)
1033 void troff_output_file::check_charinfo(tfont *tf, charinfo *ci)
1038 int height = tf->get_char_height(ci).to_units();
1039 int width = tf->get_width(ci).to_units()
1040 + tf->get_italic_correction(ci).to_units();
1041 int depth = tf->get_char_depth(ci).to_units();
1042 check_output_limits(output_hpos, output_vpos - height);
1043 check_output_limits(output_hpos + width, output_vpos + depth);
1046 void troff_output_file::put_char_width(charinfo *ci, tfont *tf,
1047 color *gcol, color *fcol,
1050 int kk = k.to_units();
1053 hpos += w.to_units() + kk;
1057 unsigned char c = ci->get_ascii_code();
1063 check_charinfo(tf, ci);
1064 if (ci->numbered()) {
1066 put(ci->get_number());
1070 const char *s = ci->nm.contents();
1079 hpos += w.to_units() + kk;
1081 else if (tcommand_flag) {
1082 if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
1083 && (!gcol || gcol == current_glyph_color)
1084 && (!fcol || fcol == current_fill_color)
1086 && tbuf_len < TBUF_SIZE) {
1087 check_charinfo(tf, ci);
1088 tbuf[tbuf_len++] = c;
1089 output_hpos += w.to_units() + kk;
1097 check_charinfo(tf, ci);
1098 tbuf[tbuf_len++] = c;
1099 output_hpos += w.to_units() + kk;
1105 int n = hpos - output_hpos;
1106 check_charinfo(tf, ci);
1107 // check_output_limits(output_hpos, output_vpos);
1108 if (vpos == output_vpos
1109 && (!gcol || gcol == current_glyph_color)
1110 && (!fcol || fcol == current_fill_color)
1111 && n > 0 && n < 100 && !force_motion) {
1112 put(char(n/10 + '0'));
1113 put(char(n%10 + '0'));
1124 hpos += w.to_units() + kk;
1128 void troff_output_file::put_char(charinfo *ci, tfont *tf,
1129 color *gcol, color *fcol)
1135 unsigned char c = ci->get_ascii_code();
1141 if (ci->numbered()) {
1143 put(ci->get_number());
1147 const char *s = ci->nm.contents();
1158 int n = hpos - output_hpos;
1159 if (vpos == output_vpos
1160 && (!gcol || gcol == current_glyph_color)
1161 && (!fcol || fcol == current_fill_color)
1162 && n > 0 && n < 100) {
1163 put(char(n/10 + '0'));
1164 put(char(n%10 + '0'));
1179 // set_font calls `flush_tbuf' if necessary.
1181 void troff_output_file::set_font(tfont *tf)
1183 if (current_tfont == tf)
1186 int n = tf->get_input_position();
1187 symbol nm = tf->get_name();
1188 if (n >= nfont_positions || font_position[n] != nm) {
1194 if (n >= nfont_positions) {
1195 int old_nfont_positions = nfont_positions;
1196 symbol *old_font_position = font_position;
1197 nfont_positions *= 3;
1198 nfont_positions /= 2;
1199 if (nfont_positions <= n)
1200 nfont_positions = n + 10;
1201 font_position = new symbol[nfont_positions];
1202 memcpy(font_position, old_font_position,
1203 old_nfont_positions*sizeof(symbol));
1204 a_delete old_font_position;
1206 font_position[n] = nm;
1208 if (current_font_number != n) {
1212 current_font_number = n;
1214 int zoom = tf->get_zoom();
1217 size = scale(tf->get_size().to_scaled_points(),
1220 size = tf->get_size().to_scaled_points();
1221 if (current_size != size) {
1225 current_size = size;
1227 int slant = tf->get_slant();
1228 if (current_slant != slant) {
1232 current_slant = slant;
1234 int height = tf->get_height();
1235 if (current_height != height) {
1237 put(height == 0 ? current_size : height);
1239 current_height = height;
1244 // fill_color calls `flush_tbuf' and `do_motion' if necessary.
1246 void troff_output_file::fill_color(color *col)
1248 if (!col || current_fill_color == col)
1250 current_fill_color = col;
1256 unsigned int components[4];
1258 cs = col->get_components(components);
1297 // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1299 void troff_output_file::glyph_color(color *col)
1301 if (!col || current_glyph_color == col)
1303 current_glyph_color = col;
1307 // grotty doesn't like a color command if the vertical position is zero.
1310 unsigned int components[4];
1312 cs = col->get_components(components);
1351 void troff_output_file::add_to_tag_list(string s)
1353 if (tag_list == string(""))
1356 tag_list += string("\n");
1361 // determine_line_limits - works out the smallest box which will contain
1362 // the entity, code, built from the point array.
1363 void troff_output_file::determine_line_limits(char code, hvpair *point,
1374 // only the h field is used when defining a circle
1375 check_output_limits(output_hpos,
1376 output_vpos - point[0].h.to_units()/2);
1377 check_output_limits(output_hpos + point[0].h.to_units(),
1378 output_vpos + point[0].h.to_units()/2);
1382 check_output_limits(output_hpos,
1383 output_vpos - point[0].v.to_units()/2);
1384 check_output_limits(output_hpos + point[0].h.to_units(),
1385 output_vpos + point[0].v.to_units()/2);
1391 check_output_limits(x, y);
1392 for (i = 0; i < npoints; i++) {
1393 x += point[i].h.to_units();
1394 y += point[i].v.to_units();
1395 check_output_limits(x, y);
1401 for (i = 0; i < npoints; i++) {
1402 x += point[i].h.to_units();
1403 y += point[i].v.to_units();
1404 check_output_limits(x, y);
1410 int minx, miny, maxx, maxy;
1413 p[0] = point[0].h.to_units();
1414 p[1] = point[0].v.to_units();
1415 p[2] = point[1].h.to_units();
1416 p[3] = point[1].v.to_units();
1417 if (adjust_arc_center(p, c)) {
1418 check_output_arc_limits(x, y,
1419 p[0], p[1], p[2], p[3],
1421 &minx, &maxx, &miny, &maxy);
1422 check_output_limits(minx, miny);
1423 check_output_limits(maxx, maxy);
1430 check_output_limits(x, y);
1431 for (i = 0; i < npoints; i++) {
1432 x += point[i].h.to_units();
1433 y += point[i].v.to_units();
1434 check_output_limits(x, y);
1440 for (i = 0; i < npoints; i++) {
1441 x += point[i].h.to_units();
1442 y += point[i].v.to_units();
1443 check_output_limits(x, y);
1448 void troff_output_file::draw(char code, hvpair *point, int npoints,
1449 font_size fsize, color *gcol, color *fcol)
1457 int size = fsize.to_scaled_points();
1458 if (current_size != size) {
1462 current_size = size;
1469 put(point[0].h.to_units());
1472 for (i = 0; i < npoints; i++) {
1474 put(point[i].h.to_units());
1476 put(point[i].v.to_units());
1478 determine_line_limits(code, point, npoints);
1481 for (i = 0; i < npoints; i++)
1482 output_hpos += point[i].h.to_units();
1485 for (i = 0; i < npoints; i++)
1486 output_vpos += point[i].v.to_units();
1493 void troff_output_file::really_on()
1500 void troff_output_file::really_off()
1505 void troff_output_file::really_put_filename(const char *filename, int po)
1517 void troff_output_file::really_begin_page(int pageno, vunits page_length)
1521 if (page_length > V0) {
1523 put(page_length.to_units());
1530 current_font_number = -1;
1532 // current_height = 0;
1533 // current_slant = 0;
1539 for (int i = 0; i < nfont_positions; i++)
1540 font_position[i] = NULL_SYMBOL;
1546 void troff_output_file::really_copy_file(hunits x, vunits y,
1547 const char *filename)
1553 FILE *ifp = include_search_path.open_file_cautious(filename);
1555 error("can't open `%1': %2", filename, strerror(errno));
1558 while ((c = getc(ifp)) != EOF)
1565 current_font_number = -1;
1566 for (int i = 0; i < nfont_positions; i++)
1567 font_position[i] = NULL_SYMBOL;
1570 void troff_output_file::really_transparent_char(unsigned char c)
1575 troff_output_file::~troff_output_file()
1577 a_delete font_position;
1580 void troff_output_file::trailer(vunits page_length)
1583 if (page_length > V0) {
1586 put(page_length.to_units());
1592 troff_output_file::troff_output_file()
1593 : current_slant(0), current_height(0), current_fill_color(0),
1594 current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0),
1597 font_position = new symbol[nfont_positions];
1602 put(units_per_inch);
1613 output_file *the_output = 0;
1615 output_file::output_file()
1619 output_file::~output_file()
1623 void output_file::trailer(vunits)
1627 void output_file::put_filename(const char *, int)
1631 void output_file::on()
1635 void output_file::off()
1639 real_output_file::real_output_file()
1640 : printing(0), output_on(1)
1642 #ifndef POPEN_MISSING
1644 if ((fp = popen(pipe_command, POPEN_WT)) != 0) {
1648 error("pipe open failed: %1", strerror(errno));
1651 #endif /* not POPEN_MISSING */
1655 real_output_file::~real_output_file()
1659 // To avoid looping, set fp to 0 before calling fatal().
1660 if (ferror(fp) || fflush(fp) < 0) {
1662 fatal("error writing output file");
1664 #ifndef POPEN_MISSING
1666 int result = pclose(fp);
1669 fatal("pclose failed");
1670 if (!WIFEXITED(result))
1671 error("output process `%1' got fatal signal %2",
1673 WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result));
1675 int exit_status = WEXITSTATUS(result);
1676 if (exit_status != 0)
1677 error("output process `%1' exited with status %2",
1678 pipe_command, exit_status);
1682 #endif /* not POPEN MISSING */
1683 if (fclose(fp) < 0) {
1685 fatal("error closing output file");
1689 void real_output_file::flush()
1692 fatal("error writing output file");
1695 int real_output_file::is_printing()
1700 void real_output_file::begin_page(int pageno, vunits page_length)
1702 printing = in_output_page_list(pageno);
1704 really_begin_page(pageno, page_length);
1707 void real_output_file::copy_file(hunits x, vunits y, const char *filename)
1709 if (printing && output_on)
1710 really_copy_file(x, y, filename);
1711 check_output_limits(x.to_units(), y.to_units());
1714 void real_output_file::transparent_char(unsigned char c)
1716 if (printing && output_on)
1717 really_transparent_char(c);
1720 void real_output_file::print_line(hunits x, vunits y, node *n,
1721 vunits before, vunits after, hunits width)
1724 really_print_line(x, y, n, before, after, width);
1725 delete_node_list(n);
1728 void real_output_file::really_copy_file(hunits, vunits, const char *)
1733 void real_output_file::put_filename(const char *filename, int po)
1735 really_put_filename(filename, po);
1738 void real_output_file::really_put_filename(const char *, int)
1742 void real_output_file::on()
1749 void real_output_file::off()
1755 int real_output_file::is_on()
1760 void real_output_file::really_on()
1764 void real_output_file::really_off()
1768 /* ascii_output_file */
1770 void ascii_output_file::really_transparent_char(unsigned char c)
1775 void ascii_output_file::really_print_line(hunits, vunits, node *n,
1776 vunits, vunits, hunits)
1779 n->ascii_print(this);
1785 void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
1787 fputs("<beginning of page>\n", fp);
1790 ascii_output_file::ascii_output_file()
1794 /* suppress_output_file */
1796 suppress_output_file::suppress_output_file()
1800 void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits)
1804 void suppress_output_file::really_begin_page(int, vunits)
1808 void suppress_output_file::really_transparent_char(unsigned char)
1812 /* glyphs, ligatures, kerns, discretionary breaks */
1814 class charinfo_node : public node {
1818 charinfo_node(charinfo *, statem *, int, node * = 0);
1819 int ends_sentence();
1820 int overlaps_vertically();
1821 int overlaps_horizontally();
1824 charinfo_node::charinfo_node(charinfo *c, statem *s, int pop, node *x)
1825 : node(x, s, pop), ci(c)
1829 int charinfo_node::ends_sentence()
1831 if (ci->ends_sentence())
1833 else if (ci->transparent())
1839 int charinfo_node::overlaps_horizontally()
1841 return ci->overlaps_horizontally();
1844 int charinfo_node::overlaps_vertically()
1846 return ci->overlaps_vertically();
1849 class glyph_node : public charinfo_node {
1850 static glyph_node *free_list;
1854 color *fcol; /* this is needed for grotty */
1857 glyph_node(charinfo *, tfont *, color *, color *, hunits,
1858 statem *, int, node * = 0);
1861 void *operator new(size_t);
1862 void operator delete(void *);
1863 glyph_node(charinfo *, tfont *, color *, color *,
1864 statem *, int, node * = 0);
1867 node *merge_glyph_node(glyph_node *);
1868 node *merge_self(node *);
1870 node *last_char_node();
1872 void vertical_extent(vunits *, vunits *);
1873 hunits subscript_correction();
1874 hunits italic_correction();
1875 hunits left_italic_correction();
1877 hyphenation_type get_hyphenation_type();
1879 color *get_glyph_color();
1880 color *get_fill_color();
1881 void tprint(troff_output_file *);
1882 void zero_width_tprint(troff_output_file *);
1883 hyphen_list *get_hyphen_list(hyphen_list *, int *);
1884 node *add_self(node *, hyphen_list **);
1885 void ascii_print(ascii_output_file *);
1886 void asciify(macro *);
1887 int character_type();
1895 glyph_node *glyph_node::free_list = 0;
1897 class ligature_node : public glyph_node {
1901 ligature_node(charinfo *, tfont *, color *, color *, hunits,
1902 node *, node *, statem *, int, node * = 0);
1905 void *operator new(size_t);
1906 void operator delete(void *);
1907 ligature_node(charinfo *, tfont *, color *, color *,
1908 node *, node *, statem *, int, node * = 0);
1911 node *add_self(node *, hyphen_list **);
1912 hyphen_list *get_hyphen_list(hyphen_list *, int *);
1913 void ascii_print(ascii_output_file *);
1914 void asciify(macro *);
1921 class kern_pair_node : public node {
1926 kern_pair_node(hunits, node *, node *, statem *, int, node * = 0);
1929 node *merge_glyph_node(glyph_node *);
1930 node *add_self(node *, hyphen_list **);
1931 hyphen_list *get_hyphen_list(hyphen_list *, int *);
1932 node *add_discretionary_hyphen();
1934 node *last_char_node();
1935 hunits italic_correction();
1936 hunits subscript_correction();
1937 void tprint(troff_output_file *);
1938 hyphenation_type get_hyphenation_type();
1939 int ends_sentence();
1940 void ascii_print(ascii_output_file *);
1941 void asciify(macro *);
1946 void vertical_extent(vunits *, vunits *);
1949 class dbreak_node : public node {
1954 dbreak_node(node *, node *, statem *, int, node * = 0);
1957 node *merge_glyph_node(glyph_node *);
1958 node *add_discretionary_hyphen();
1960 node *last_char_node();
1961 hunits italic_correction();
1962 hunits subscript_correction();
1963 void tprint(troff_output_file *);
1964 breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
1967 int ends_sentence();
1968 void split(int, node **, node **);
1969 hyphenation_type get_hyphenation_type();
1970 void ascii_print(ascii_output_file *);
1971 void asciify(macro *);
1978 void *glyph_node::operator new(size_t n)
1980 assert(n == sizeof(glyph_node));
1982 const int BLOCK = 1024;
1983 free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
1984 for (int i = 0; i < BLOCK - 1; i++)
1985 free_list[i].next = free_list + i + 1;
1986 free_list[BLOCK-1].next = 0;
1988 glyph_node *p = free_list;
1989 free_list = (glyph_node *)(free_list->next);
1994 void *ligature_node::operator new(size_t n)
1999 void glyph_node::operator delete(void *p)
2002 ((glyph_node *)p)->next = free_list;
2003 free_list = (glyph_node *)p;
2007 void ligature_node::operator delete(void *p)
2012 glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc,
2013 statem *s, int pop, node *x)
2014 : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc)
2017 wid = tf->get_width(ci);
2022 glyph_node::glyph_node(charinfo *c, tfont *t,
2023 color *gc, color *fc, hunits w,
2024 statem *s, int pop, node *x)
2025 : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc), wid(w)
2030 node *glyph_node::copy()
2033 return new glyph_node(ci, tf, gcol, fcol, wid, state, div_nest_level);
2035 return new glyph_node(ci, tf, gcol, fcol, state, div_nest_level);
2039 node *glyph_node::merge_self(node *nd)
2041 return nd->merge_glyph_node(this);
2044 int glyph_node::character_type()
2046 return tf->get_character_type(ci);
2049 node *glyph_node::add_self(node *n, hyphen_list **p)
2051 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
2054 if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
2059 nn = nn->add_discretionary_hyphen();
2060 hyphen_list *pp = *p;
2066 units glyph_node::size()
2068 return tf->get_size().to_units();
2071 hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail, int *count)
2074 return new hyphen_list(ci->get_hyphenation_code(), tail);
2077 tfont *node::get_tfont()
2082 tfont *glyph_node::get_tfont()
2087 color *node::get_glyph_color()
2092 color *glyph_node::get_glyph_color()
2097 color *node::get_fill_color()
2102 color *glyph_node::get_fill_color()
2107 node *node::merge_glyph_node(glyph_node *)
2112 node *glyph_node::merge_glyph_node(glyph_node *gn)
2114 if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) {
2116 if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
2119 return new ligature_node(lig, tf, gcol, fcol, this, gn, state,
2120 gn->div_nest_level, next1);
2123 if (tf->get_kern(ci, gn->ci, &kern)) {
2126 return new kern_pair_node(kern, this, gn, state,
2127 gn->div_nest_level, next1);
2136 hunits glyph_node::width()
2141 return tf->get_width(ci);
2145 node *glyph_node::last_char_node()
2150 void glyph_node::vertical_extent(vunits *min, vunits *max)
2152 *min = -tf->get_char_height(ci);
2153 *max = tf->get_char_depth(ci);
2156 hunits glyph_node::skew()
2158 return tf->get_char_skew(ci);
2161 hunits glyph_node::subscript_correction()
2163 return tf->get_subscript_correction(ci);
2166 hunits glyph_node::italic_correction()
2168 return tf->get_italic_correction(ci);
2171 hunits glyph_node::left_italic_correction()
2173 return tf->get_left_italic_correction(ci);
2176 hyphenation_type glyph_node::get_hyphenation_type()
2178 return HYPHEN_MIDDLE;
2181 void glyph_node::ascii_print(ascii_output_file *ascii)
2183 unsigned char c = ci->get_ascii_code();
2187 ascii->outs(ci->nm.contents());
2190 void glyph_node::debug_node()
2192 unsigned char c = ci->get_ascii_code();
2193 fprintf(stderr, "{ %s [", type());
2195 fprintf(stderr, "%c", c);
2197 fprintf(stderr, "%s", ci->nm.contents());
2199 fprintf(stderr, " <push_state>");
2201 state->display_state();
2202 fprintf(stderr, " nest level %d", div_nest_level);
2203 fprintf(stderr, "]}\n");
2207 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2208 node *gn1, node *gn2, statem *s,
2210 : glyph_node(c, t, gc, fc, s, pop, x), n1(gn1), n2(gn2)
2215 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2216 hunits w, node *gn1, node *gn2, statem *s,
2218 : glyph_node(c, t, gc, fc, w, s, pop, x), n1(gn1), n2(gn2)
2223 ligature_node::~ligature_node()
2229 node *ligature_node::copy()
2232 return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy(),
2233 state, div_nest_level);
2235 return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy(),
2236 state, div_nest_level);
2240 void ligature_node::ascii_print(ascii_output_file *ascii)
2242 n1->ascii_print(ascii);
2243 n2->ascii_print(ascii);
2246 hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail, int *count)
2248 hyphen_list *hl = n2->get_hyphen_list(tail, count);
2249 return n1->get_hyphen_list(hl, count);
2252 node *ligature_node::add_self(node *n, hyphen_list **p)
2254 n = n1->add_self(n, p);
2255 n = n2->add_self(n, p);
2261 kern_pair_node::kern_pair_node(hunits n, node *first, node *second,
2262 statem* s, int pop, node *x)
2263 : node(x, s, pop), amount(n), n1(first), n2(second)
2267 dbreak_node::dbreak_node(node *n, node *p, statem *s, int pop, node *x)
2268 : node(x, s, pop), none(n), pre(p), post(0)
2272 node *dbreak_node::merge_glyph_node(glyph_node *gn)
2274 glyph_node *gn2 = (glyph_node *)gn->copy();
2275 node *new_none = none ? none->merge_glyph_node(gn) : 0;
2276 node *new_post = post ? post->merge_glyph_node(gn2) : 0;
2277 if (new_none == 0 && new_post == 0) {
2296 node *kern_pair_node::merge_glyph_node(glyph_node *gn)
2298 node *nd = n2->merge_glyph_node(gn);
2302 nd = n2->merge_self(n1);
2313 hunits kern_pair_node::italic_correction()
2315 return n2->italic_correction();
2318 hunits kern_pair_node::subscript_correction()
2320 return n2->subscript_correction();
2323 void kern_pair_node::vertical_extent(vunits *min, vunits *max)
2325 n1->vertical_extent(min, max);
2327 n2->vertical_extent(&min2, &max2);
2334 node *kern_pair_node::add_discretionary_hyphen()
2336 tfont *tf = n1->get_tfont();
2338 if (tf->contains(soft_hyphen_char)) {
2339 color *gcol = n2->get_glyph_color();
2340 color *fcol = n2->get_fill_color();
2344 glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol,
2345 state, div_nest_level);
2346 node *nn = n->merge_glyph_node(gn);
2351 return new dbreak_node(this, nn, state, div_nest_level, next1);
2357 kern_pair_node::~kern_pair_node()
2365 dbreak_node::~dbreak_node()
2367 delete_node_list(pre);
2368 delete_node_list(post);
2369 delete_node_list(none);
2372 node *kern_pair_node::copy()
2374 return new kern_pair_node(amount, n1->copy(), n2->copy(), state,
2378 node *copy_node_list(node *n)
2382 node *nn = n->copy();
2396 void delete_node_list(node *n)
2405 node *dbreak_node::copy()
2407 dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre),
2408 state, div_nest_level);
2409 p->post = copy_node_list(post);
2413 hyphen_list *node::get_hyphen_list(hyphen_list *tail, int *)
2418 hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail, int *count)
2420 hyphen_list *hl = n2->get_hyphen_list(tail, count);
2421 return n1->get_hyphen_list(hl, count);
2424 class hyphen_inhibitor_node : public node {
2426 hyphen_inhibitor_node(node * = 0);
2432 hyphenation_type get_hyphenation_type();
2435 hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd)
2439 node *hyphen_inhibitor_node::copy()
2441 return new hyphen_inhibitor_node;
2444 int hyphen_inhibitor_node::same(node *)
2449 const char *hyphen_inhibitor_node::type()
2451 return "hyphen_inhibitor_node";
2454 int hyphen_inhibitor_node::force_tprint()
2459 int hyphen_inhibitor_node::is_tag()
2464 hyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
2466 return HYPHEN_INHIBIT;
2469 /* add_discretionary_hyphen methods */
2471 node *dbreak_node::add_discretionary_hyphen()
2474 post = post->add_discretionary_hyphen();
2476 none = none->add_discretionary_hyphen();
2480 node *node::add_discretionary_hyphen()
2482 tfont *tf = get_tfont();
2484 return new hyphen_inhibitor_node(this);
2485 if (tf->contains(soft_hyphen_char)) {
2486 color *gcol = get_glyph_color();
2487 color *fcol = get_fill_color();
2491 glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol,
2492 state, div_nest_level);
2493 node *n1 = n->merge_glyph_node(gn);
2498 return new dbreak_node(this, n1, state, div_nest_level, next1);
2503 node *node::merge_self(node *)
2508 node *node::add_self(node *n, hyphen_list ** /*p*/)
2514 node *kern_pair_node::add_self(node *n, hyphen_list **p)
2516 n = n1->add_self(n, p);
2517 n = n2->add_self(n, p);
2523 hunits node::width()
2528 node *node::last_char_node()
2533 int node::force_tprint()
2543 int node::get_break_code()
2548 hunits hmotion_node::width()
2555 return points_to_units(10);
2558 void node::debug_node()
2560 fprintf(stderr, "{ %s ", type());
2562 fprintf(stderr, " <push_state>");
2564 fprintf(stderr, " <state>");
2565 fprintf(stderr, " nest level %d", div_nest_level);
2566 fprintf(stderr, " }\n");
2570 void node::debug_node_list()
2581 hunits kern_pair_node::width()
2583 return n1->width() + n2->width() + amount;
2586 node *kern_pair_node::last_char_node()
2588 node *nd = n2->last_char_node();
2591 return n1->last_char_node();
2594 hunits dbreak_node::width()
2597 for (node *n = none; n != 0; n = n->next)
2602 node *dbreak_node::last_char_node()
2604 for (node *n = none; n; n = n->next) {
2605 node *last_node = n->last_char_node();
2612 hunits dbreak_node::italic_correction()
2614 return none ? none->italic_correction() : H0;
2617 hunits dbreak_node::subscript_correction()
2619 return none ? none->subscript_correction() : H0;
2622 class italic_corrected_node : public node {
2626 italic_corrected_node(node *, hunits, statem *, int, node * = 0);
2627 ~italic_corrected_node();
2629 void ascii_print(ascii_output_file *);
2630 void asciify(macro *);
2632 node *last_char_node();
2633 void vertical_extent(vunits *, vunits *);
2634 int ends_sentence();
2635 int overlaps_horizontally();
2636 int overlaps_vertically();
2638 hyphenation_type get_hyphenation_type();
2640 hyphen_list *get_hyphen_list(hyphen_list *, int *);
2641 int character_type();
2642 void tprint(troff_output_file *);
2643 hunits subscript_correction();
2645 node *add_self(node *, hyphen_list **);
2651 node *node::add_italic_correction(hunits *wd)
2653 hunits ic = italic_correction();
2660 return new italic_corrected_node(this, ic, state, div_nest_level, next1);
2664 italic_corrected_node::italic_corrected_node(node *nn, hunits xx, statem *s,
2666 : node(p, s, pop), n(nn), x(xx)
2671 italic_corrected_node::~italic_corrected_node()
2676 node *italic_corrected_node::copy()
2678 return new italic_corrected_node(n->copy(), x, state, div_nest_level);
2681 hunits italic_corrected_node::width()
2683 return n->width() + x;
2686 void italic_corrected_node::vertical_extent(vunits *min, vunits *max)
2688 n->vertical_extent(min, max);
2691 void italic_corrected_node::tprint(troff_output_file *out)
2697 hunits italic_corrected_node::skew()
2699 return n->skew() - x/2;
2702 hunits italic_corrected_node::subscript_correction()
2704 return n->subscript_correction() - x;
2707 void italic_corrected_node::ascii_print(ascii_output_file *out)
2709 n->ascii_print(out);
2712 int italic_corrected_node::ends_sentence()
2714 return n->ends_sentence();
2717 int italic_corrected_node::overlaps_horizontally()
2719 return n->overlaps_horizontally();
2722 int italic_corrected_node::overlaps_vertically()
2724 return n->overlaps_vertically();
2727 node *italic_corrected_node::last_char_node()
2729 return n->last_char_node();
2732 tfont *italic_corrected_node::get_tfont()
2734 return n->get_tfont();
2737 hyphenation_type italic_corrected_node::get_hyphenation_type()
2739 return n->get_hyphenation_type();
2742 node *italic_corrected_node::add_self(node *nd, hyphen_list **p)
2744 nd = n->add_self(nd, p);
2745 hunits not_interested;
2746 nd = nd->add_italic_correction(¬_interested);
2752 hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail,
2755 return n->get_hyphen_list(tail, count);
2758 int italic_corrected_node::character_type()
2760 return n->character_type();
2763 class break_char_node : public node {
2766 char prev_break_code;
2769 break_char_node(node *, int, int, color *, node * = 0);
2770 break_char_node(node *, int, int, color *, statem *, int, node * = 0);
2774 vunits vertical_width();
2775 node *last_char_node();
2776 int character_type();
2777 int ends_sentence();
2778 node *add_self(node *, hyphen_list **);
2779 hyphen_list *get_hyphen_list(hyphen_list *, int *);
2780 void tprint(troff_output_file *);
2781 void zero_width_tprint(troff_output_file *);
2782 void ascii_print(ascii_output_file *);
2783 void asciify(macro *);
2784 hyphenation_type get_hyphenation_type();
2785 int overlaps_vertically();
2786 int overlaps_horizontally();
2793 int get_break_code();
2796 break_char_node::break_char_node(node *n, int bc, int pbc, color *c, node *x)
2797 : node(x), ch(n), break_code(bc), prev_break_code(pbc), col(c)
2801 break_char_node::break_char_node(node *n, int bc, int pbc, color *c,
2802 statem *s, int pop, node *x)
2803 : node(x, s, pop), ch(n), break_code(bc), prev_break_code(pbc), col(c)
2807 break_char_node::~break_char_node()
2812 node *break_char_node::copy()
2814 return new break_char_node(ch->copy(), break_code, prev_break_code,
2815 col, state, div_nest_level);
2818 hunits break_char_node::width()
2823 vunits break_char_node::vertical_width()
2825 return ch->vertical_width();
2828 node *break_char_node::last_char_node()
2830 return ch->last_char_node();
2833 int break_char_node::character_type()
2835 return ch->character_type();
2838 int break_char_node::ends_sentence()
2840 return ch->ends_sentence();
2843 enum break_char_type {
2844 CAN_BREAK_BEFORE = 0x01,
2845 CAN_BREAK_AFTER = 0x02,
2846 IGNORE_HCODES = 0x04,
2847 PROHIBIT_BREAK_BEFORE = 0x08,
2848 PROHIBIT_BREAK_AFTER = 0x10,
2849 INTER_CHAR_SPACE = 0x20
2852 node *break_char_node::add_self(node *n, hyphen_list **p)
2854 int have_space_node = 0;
2855 assert((*p)->hyphenation_code == 0);
2856 if (break_code & CAN_BREAK_BEFORE) {
2857 if ((*p)->breakable || break_code & IGNORE_HCODES) {
2858 n = new space_node(H0, col, n);
2860 have_space_node = 1;
2863 if (!have_space_node) {
2864 if (prev_break_code & INTER_CHAR_SPACE
2865 || prev_break_code & PROHIBIT_BREAK_AFTER) {
2866 if (break_code & PROHIBIT_BREAK_BEFORE)
2867 // stretchable zero-width space not implemented yet
2870 // breakable, stretchable zero-width space not implemented yet
2871 n = new space_node(H0, col, n);
2878 if (break_code & CAN_BREAK_AFTER) {
2879 if ((*p)->breakable || break_code & IGNORE_HCODES) {
2880 n = new space_node(H0, col, n);
2884 hyphen_list *pp = *p;
2890 hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail, int *)
2892 return new hyphen_list(0, tail);
2895 hyphenation_type break_char_node::get_hyphenation_type()
2897 return HYPHEN_MIDDLE;
2900 void break_char_node::ascii_print(ascii_output_file *ascii)
2902 ch->ascii_print(ascii);
2905 int break_char_node::overlaps_vertically()
2907 return ch->overlaps_vertically();
2910 int break_char_node::overlaps_horizontally()
2912 return ch->overlaps_horizontally();
2915 units break_char_node::size()
2920 tfont *break_char_node::get_tfont()
2922 return ch->get_tfont();
2925 node *extra_size_node::copy()
2927 return new extra_size_node(n, state, div_nest_level);
2930 extra_size_node::extra_size_node(vunits i, statem *s, int pop)
2931 : node(0, s, pop), n(i)
2935 extra_size_node::extra_size_node(vunits i)
2940 node *vertical_size_node::copy()
2942 return new vertical_size_node(n, state, div_nest_level);
2945 vertical_size_node::vertical_size_node(vunits i, statem *s, int pop)
2946 : node(0, s, pop), n(i)
2950 vertical_size_node::vertical_size_node(vunits i)
2955 node *hmotion_node::copy()
2957 return new hmotion_node(n, was_tab, unformat, col, state, div_nest_level);
2960 node *space_char_hmotion_node::copy()
2962 return new space_char_hmotion_node(n, col, state, div_nest_level);
2965 vmotion_node::vmotion_node(vunits i, color *c)
2970 vmotion_node::vmotion_node(vunits i, color *c, statem *s, int pop)
2971 : node(0, s, pop), n(i), col(c)
2975 node *vmotion_node::copy()
2977 return new vmotion_node(n, col, state, div_nest_level);
2980 node *dummy_node::copy()
2982 return new dummy_node;
2985 node *transparent_dummy_node::copy()
2987 return new transparent_dummy_node;
2990 hline_node::~hline_node()
2996 hline_node::hline_node(hunits i, node *c, node *nxt)
2997 : node(nxt), x(i), n(c)
3001 hline_node::hline_node(hunits i, node *c, statem *s, int pop, node *nxt)
3002 : node(nxt, s, pop), x(i), n(c)
3006 node *hline_node::copy()
3008 return new hline_node(x, n ? n->copy() : 0, state, div_nest_level);
3011 hunits hline_node::width()
3013 return x < H0 ? H0 : x;
3016 vline_node::vline_node(vunits i, node *c, node *nxt)
3017 : node(nxt), x(i), n(c)
3021 vline_node::vline_node(vunits i, node *c, statem *s, int pop, node *nxt)
3022 : node(nxt, s, pop), x(i), n(c)
3026 vline_node::~vline_node()
3032 node *vline_node::copy()
3034 return new vline_node(x, n ? n->copy() : 0, state, div_nest_level);
3037 hunits vline_node::width()
3039 return n == 0 ? H0 : n->width();
3042 zero_width_node::zero_width_node(node *nd, statem *s, int pop)
3043 : node(0, s, pop), n(nd)
3047 zero_width_node::zero_width_node(node *nd)
3052 zero_width_node::~zero_width_node()
3054 delete_node_list(n);
3057 node *zero_width_node::copy()
3059 return new zero_width_node(copy_node_list(n), state, div_nest_level);
3062 int node_list_character_type(node *p)
3065 for (; p; p = p->next)
3066 t |= p->character_type();
3070 int zero_width_node::character_type()
3072 return node_list_character_type(n);
3075 void node_list_vertical_extent(node *p, vunits *min, vunits *max)
3079 vunits cur_vpos = V0;
3081 for (; p; p = p->next) {
3082 p->vertical_extent(&v1, &v2);
3089 cur_vpos += p->vertical_width();
3093 void zero_width_node::vertical_extent(vunits *min, vunits *max)
3095 node_list_vertical_extent(n, min, max);
3098 overstrike_node::overstrike_node()
3099 : list(0), max_width(H0)
3103 overstrike_node::overstrike_node(statem *s, int pop)
3104 : node(0, s, pop), list(0), max_width(H0)
3108 overstrike_node::~overstrike_node()
3110 delete_node_list(list);
3113 node *overstrike_node::copy()
3115 overstrike_node *on = new overstrike_node(state, div_nest_level);
3116 for (node *tem = list; tem; tem = tem->next)
3117 on->overstrike(tem->copy());
3121 void overstrike_node::overstrike(node *n)
3125 hunits w = n->width();
3129 for (p = &list; *p; p = &(*p)->next)
3135 hunits overstrike_node::width()
3140 bracket_node::bracket_node()
3141 : list(0), max_width(H0)
3145 bracket_node::bracket_node(statem *s, int pop)
3146 : node(0, s, pop), list(0), max_width(H0)
3150 bracket_node::~bracket_node()
3152 delete_node_list(list);
3155 node *bracket_node::copy()
3157 bracket_node *on = new bracket_node(state, div_nest_level);
3158 node *last_node = 0;
3162 for (tem = list; tem; tem = tem->next) {
3164 tem->next->last = tem;
3167 for (tem = last_node; tem; tem = tem->last)
3168 on->bracket(tem->copy());
3172 void bracket_node::bracket(node *n)
3176 hunits w = n->width();
3183 hunits bracket_node::width()
3193 int node::merge_space(hunits, hunits, hunits)
3199 space_node *space_node::free_list = 0;
3201 void *space_node::operator new(size_t n)
3203 assert(n == sizeof(space_node));
3205 free_list = (space_node *)new char[sizeof(space_node)*BLOCK];
3206 for (int i = 0; i < BLOCK - 1; i++)
3207 free_list[i].next = free_list + i + 1;
3208 free_list[BLOCK-1].next = 0;
3210 space_node *p = free_list;
3211 free_list = (space_node *)(free_list->next);
3216 inline void space_node::operator delete(void *p)
3219 ((space_node *)p)->next = free_list;
3220 free_list = (space_node *)p;
3225 space_node::space_node(hunits nn, color *c, node *p)
3226 : node(p, 0, 0), n(nn), set(0), was_escape_colon(0), col(c)
3230 space_node::space_node(hunits nn, int s, int flag, color *c, statem *st,
3232 : node(p, st, pop), n(nn), set(s), was_escape_colon(flag), col(c)
3237 space_node::~space_node()
3242 node *space_node::copy()
3244 return new space_node(n, set, was_escape_colon, col, state, div_nest_level);
3247 int space_node::force_tprint()
3252 int space_node::is_tag()
3257 int space_node::nspaces()
3262 int space_node::merge_space(hunits h, hunits, hunits)
3268 hunits space_node::width()
3273 void node::spread_space(int*, hunits*)
3277 void space_node::spread_space(int *n_spaces, hunits *desired_space)
3280 assert(*n_spaces > 0);
3281 if (*n_spaces == 1) {
3282 n += *desired_space;
3283 *desired_space = H0;
3286 hunits extra = *desired_space / *n_spaces;
3287 *desired_space -= extra;
3295 void node::freeze_space()
3299 void space_node::freeze_space()
3304 void node::is_escape_colon()
3308 void space_node::is_escape_colon()
3310 was_escape_colon = 1;
3313 diverted_space_node::diverted_space_node(vunits d, statem *s, int pop,
3315 : node(p, s, pop), n(d)
3319 diverted_space_node::diverted_space_node(vunits d, node *p)
3324 node *diverted_space_node::copy()
3326 return new diverted_space_node(n, state, div_nest_level);
3329 diverted_copy_file_node::diverted_copy_file_node(symbol s, statem *st,
3331 : node(p, st, pop), filename(s)
3335 diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p)
3336 : node(p), filename(s)
3340 node *diverted_copy_file_node::copy()
3342 return new diverted_copy_file_node(filename, state, div_nest_level);
3345 int node::ends_sentence()
3350 int kern_pair_node::ends_sentence()
3352 switch (n2->ends_sentence()) {
3362 return n1->ends_sentence();
3365 int node_list_ends_sentence(node *n)
3367 for (; n != 0; n = n->next)
3368 switch (n->ends_sentence()) {
3381 int dbreak_node::ends_sentence()
3383 return node_list_ends_sentence(none);
3386 int node::overlaps_horizontally()
3391 int node::overlaps_vertically()
3396 int node::discardable()
3401 int space_node::discardable()
3406 vunits node::vertical_width()
3411 vunits vline_node::vertical_width()
3416 vunits vmotion_node::vertical_width()
3421 int node::set_unformat_flag()
3426 int node::character_type()
3431 hunits node::subscript_correction()
3436 hunits node::italic_correction()
3441 hunits node::left_italic_correction()
3451 /* vertical_extent methods */
3453 void node::vertical_extent(vunits *min, vunits *max)
3455 vunits v = vertical_width();
3466 void vline_node::vertical_extent(vunits *min, vunits *max)
3469 node::vertical_extent(min, max);
3472 n->vertical_extent(&cmin, &cmax);
3473 vunits h = n->size();
3480 // we print the first character and then move up, so
3482 // we print the last character and then move up h
3495 // we move down by h and then print the first character, so
3505 /* ascii_print methods */
3507 static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n)
3511 ascii_print_reverse_node_list(ascii, n->next);
3512 n->ascii_print(ascii);
3515 void dbreak_node::ascii_print(ascii_output_file *ascii)
3517 ascii_print_reverse_node_list(ascii, none);
3520 void kern_pair_node::ascii_print(ascii_output_file *ascii)
3522 n1->ascii_print(ascii);
3523 n2->ascii_print(ascii);
3526 void node::ascii_print(ascii_output_file *)
3530 void space_node::ascii_print(ascii_output_file *ascii)
3536 void hmotion_node::ascii_print(ascii_output_file *ascii)
3538 // this is pretty arbitrary
3539 if (n >= points_to_units(2))
3543 void space_char_hmotion_node::ascii_print(ascii_output_file *ascii)
3548 /* asciify methods */
3550 void node::asciify(macro *m)
3555 void glyph_node::asciify(macro *m)
3557 unsigned char c = ci->get_asciify_code();
3559 c = ci->get_ascii_code();
3568 void kern_pair_node::asciify(macro *m)
3576 static void asciify_reverse_node_list(macro *m, node *n)
3580 asciify_reverse_node_list(m, n->next);
3584 void dbreak_node::asciify(macro *m)
3586 asciify_reverse_node_list(m, none);
3591 void ligature_node::asciify(macro *m)
3599 void break_char_node::asciify(macro *m)
3606 void italic_corrected_node::asciify(macro *m)
3613 void left_italic_corrected_node::asciify(macro *m)
3622 void hmotion_node::asciify(macro *m)
3632 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3635 : hmotion_node(i, c, s, pop, nxt)
3639 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3641 : hmotion_node(i, c, 0, 0, nxt)
3645 void space_char_hmotion_node::asciify(macro *m)
3647 m->append(ESCAPE_SPACE);
3651 void space_node::asciify(macro *m)
3653 if (was_escape_colon) {
3654 m->append(ESCAPE_COLON);
3661 void word_space_node::asciify(macro *m)
3663 for (width_list *w = orig_width; w; w = w->next)
3668 void unbreakable_space_node::asciify(macro *m)
3670 m->append(ESCAPE_TILDE);
3674 void line_start_node::asciify(macro *)
3679 void vertical_size_node::asciify(macro *)
3684 breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/,
3685 breakpoint *rest, int /*is_inner*/)
3695 breakpoint *space_node::get_breakpoints(hunits wd, int ns,
3696 breakpoint *rest, int is_inner)
3698 if (next && next->discardable())
3700 breakpoint *bp = new breakpoint;
3707 bp->index = rest->index + 1;
3717 int space_node::nbreaks()
3719 if (next && next->discardable())
3725 static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp,
3726 int ns, breakpoint *rest)
3729 rest = p->get_breakpoints(*widthp,
3731 node_list_get_breakpoints(p->next, widthp, ns,
3734 *widthp += p->width();
3739 breakpoint *dbreak_node::get_breakpoints(hunits wd, int ns,
3740 breakpoint *rest, int is_inner)
3742 breakpoint *bp = new breakpoint;
3745 for (node *tem = pre; tem != 0; tem = tem->next)
3746 bp->width += tem->width();
3751 bp->index = rest->index + 1;
3758 return node_list_get_breakpoints(none, &wd, ns, bp);
3761 int dbreak_node::nbreaks()
3764 for (node *tem = none; tem != 0; tem = tem->next)
3765 i += tem->nbreaks();
3769 void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/)
3774 void space_node::split(int where, node **pre, node **post)
3782 static void node_list_split(node *p, int *wherep, node **prep, node **postp)
3786 int nb = p->nbreaks();
3787 node_list_split(p->next, wherep, prep, postp);
3792 else if (*wherep < nb) {
3794 p->split(*wherep, prep, postp);
3803 void dbreak_node::split(int where, node **prep, node **postp)
3813 for (tem = pre; tem->next != 0; tem = tem->next)
3824 node_list_split(none, &where, prep, postp);
3830 hyphenation_type node::get_hyphenation_type()
3832 return HYPHEN_BOUNDARY;
3835 hyphenation_type dbreak_node::get_hyphenation_type()
3837 return HYPHEN_INHIBIT;
3840 hyphenation_type kern_pair_node::get_hyphenation_type()
3842 return HYPHEN_MIDDLE;
3845 hyphenation_type dummy_node::get_hyphenation_type()
3847 return HYPHEN_MIDDLE;
3850 hyphenation_type transparent_dummy_node::get_hyphenation_type()
3852 return HYPHEN_MIDDLE;
3855 hyphenation_type hmotion_node::get_hyphenation_type()
3857 return HYPHEN_MIDDLE;
3860 hyphenation_type space_char_hmotion_node::get_hyphenation_type()
3862 return HYPHEN_MIDDLE;
3865 hyphenation_type overstrike_node::get_hyphenation_type()
3867 return HYPHEN_MIDDLE;
3870 hyphenation_type space_node::get_hyphenation_type()
3872 if (was_escape_colon)
3873 return HYPHEN_MIDDLE;
3874 return HYPHEN_BOUNDARY;
3877 hyphenation_type unbreakable_space_node::get_hyphenation_type()
3879 return HYPHEN_MIDDLE;
3882 int node::interpret(macro *)
3887 special_node::special_node(const macro &m, int n)
3888 : mac(m), no_init_string(n)
3890 font_size fs = curenv->get_font_size();
3891 int char_height = curenv->get_char_height();
3892 int char_slant = curenv->get_char_slant();
3893 int fontno = env_definite_font(curenv);
3894 tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno);
3895 if (curenv->is_composite())
3896 tf = tf->get_plain();
3897 gcol = curenv->get_glyph_color();
3898 fcol = curenv->get_fill_color();
3902 special_node::special_node(const macro &m, tfont *t,
3903 color *gc, color *fc,
3906 : node(0, s, pop), mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n)
3911 int special_node::same(node *n)
3913 return mac == ((special_node *)n)->mac
3914 && tf == ((special_node *)n)->tf
3915 && gcol == ((special_node *)n)->gcol
3916 && fcol == ((special_node *)n)->fcol
3917 && no_init_string == ((special_node *)n)->no_init_string;
3920 const char *special_node::type()
3922 return "special_node";
3925 int special_node::ends_sentence()
3930 int special_node::force_tprint()
3935 int special_node::is_tag()
3940 node *special_node::copy()
3942 return new special_node(mac, tf, gcol, fcol, state, div_nest_level,
3946 void special_node::tprint_start(troff_output_file *out)
3948 out->start_special(tf, gcol, fcol, no_init_string);
3951 void special_node::tprint_char(troff_output_file *out, unsigned char c)
3953 out->special_char(c);
3956 void special_node::tprint_end(troff_output_file *out)
3961 tfont *special_node::get_tfont()
3968 suppress_node::suppress_node(int on_or_off, int issue_limits)
3969 : is_on(on_or_off), emit_limits(issue_limits), filename(0), position(0),
3974 suppress_node::suppress_node(symbol f, char p, int id)
3975 : is_on(2), emit_limits(0), filename(f), position(p), image_id(id)
3980 suppress_node::suppress_node(int issue_limits, int on_or_off,
3981 symbol f, char p, int id,
3983 : node(0, s, pop), is_on(on_or_off), emit_limits(issue_limits), filename(f),
3984 position(p), image_id(id)
3988 int suppress_node::same(node *n)
3990 return ((is_on == ((suppress_node *)n)->is_on)
3991 && (emit_limits == ((suppress_node *)n)->emit_limits)
3992 && (filename == ((suppress_node *)n)->filename)
3993 && (position == ((suppress_node *)n)->position)
3994 && (image_id == ((suppress_node *)n)->image_id));
3997 const char *suppress_node::type()
3999 return "suppress_node";
4002 node *suppress_node::copy()
4004 return new suppress_node(emit_limits, is_on, filename, position, image_id,
4005 state, div_nest_level);
4010 tag_node::tag_node()
4016 tag_node::tag_node(string s, int delay)
4017 : tag_string(s), delayed(delay)
4019 is_special = !delay;
4022 tag_node::tag_node(string s, statem *st, int pop, int delay)
4023 : node(0, st, pop), tag_string(s), delayed(delay)
4025 is_special = !delay;
4028 node *tag_node::copy()
4030 return new tag_node(tag_string, state, div_nest_level, delayed);
4033 void tag_node::tprint(troff_output_file *out)
4036 out->add_to_tag_list(tag_string);
4038 out->state.add_tag(out->fp, tag_string);
4041 int tag_node::same(node *nd)
4043 return tag_string == ((tag_node *)nd)->tag_string
4044 && delayed == ((tag_node *)nd)->delayed;
4047 const char *tag_node::type()
4052 int tag_node::force_tprint()
4057 int tag_node::is_tag()
4062 int tag_node::ends_sentence()
4067 int get_reg_int(const char *p)
4069 reg *r = (reg *)number_reg_dictionary.lookup(p);
4071 if (r && (r->get_value(&prev_value)))
4072 return (int)prev_value;
4074 warning(WARN_REG, "number register `%1' not defined", p);
4078 const char *get_reg_str(const char *p)
4080 reg *r = (reg *)number_reg_dictionary.lookup(p);
4082 return r->get_string();
4084 warning(WARN_REG, "register `%1' not defined", p);
4088 void suppress_node::put(troff_output_file *out, const char *s)
4091 while (s[i] != (char)0) {
4092 out->special_char(s[i]);
4098 * We need to remember the start of the image and its name.
4101 static char last_position = 0;
4102 static const char *last_image_filename = 0;
4103 static int last_image_id = 0;
4105 inline int min(int a, int b)
4107 return a < b ? a : b;
4111 * tprint - if (is_on == 2)
4112 * remember current position (l, r, c, i) and filename
4118 * emit postscript bounds for image
4120 * if (suppress boolean differs from current state)
4123 * record current page
4124 * set low water mark.
4127 void suppress_node::tprint(troff_output_file *out)
4129 int current_page = topdiv->get_page_number();
4130 // firstly check to see whether this suppress node contains
4131 // an image filename & position.
4133 // remember position and filename
4134 last_position = position;
4135 char *tem = (char *)last_image_filename;
4136 last_image_filename = strsave(filename.contents());
4139 last_image_id = image_id;
4140 // printf("start of image and page = %d\n", current_page);
4143 // now check whether the suppress node requires us to issue limits.
4146 // remember that the filename will contain a %d in which the
4147 // last_image_id is placed
4148 if (last_image_filename == (char *) 0)
4151 sprintf(name, last_image_filename, last_image_id);
4153 switch (last_position) {
4155 out->start_special();
4156 put(out, "devtag:.centered-image");
4159 out->start_special();
4160 put(out, "devtag:.right-image");
4163 out->start_special();
4164 put(out, "devtag:.left-image");
4172 out->start_special();
4173 put(out, "devtag:.auto-image ");
4178 // postscript (or other device)
4179 if (suppress_start_page > 0 && current_page != suppress_start_page)
4180 error("suppression limit registers span more than one page;\n"
4181 "image description %1 will be wrong", image_no);
4182 // if (topdiv->get_page_number() != suppress_start_page)
4183 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
4184 // topdiv->get_page_number(), suppress_start_page);
4186 // remember that the filename will contain a %d in which the
4187 // image_no is placed
4189 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
4190 topdiv->get_page_number(),
4191 get_reg_int("opminx"), get_reg_int("opminy"),
4192 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
4193 // page offset + line length
4194 get_reg_int(".o") + get_reg_int(".l"),
4195 name, hresolution, vresolution, get_reg_str(".F"));
4202 // lastly we reset the output registers
4203 reset_output_registers();
4207 suppress_start_page = current_page;
4212 int suppress_node::force_tprint()
4217 int suppress_node::is_tag()
4222 hunits suppress_node::width()
4227 /* composite_node */
4229 class composite_node : public charinfo_node {
4233 composite_node(node *, charinfo *, tfont *, statem *, int, node * = 0);
4237 node *last_char_node();
4239 void tprint(troff_output_file *);
4240 hyphenation_type get_hyphenation_type();
4241 void ascii_print(ascii_output_file *);
4242 void asciify(macro *);
4243 hyphen_list *get_hyphen_list(hyphen_list *, int *);
4244 node *add_self(node *, hyphen_list **);
4250 void vertical_extent(vunits *, vunits *);
4251 vunits vertical_width();
4254 composite_node::composite_node(node *p, charinfo *c, tfont *t, statem *s,
4256 : charinfo_node(c, s, pop, x), n(p), tf(t)
4260 composite_node::~composite_node()
4262 delete_node_list(n);
4265 node *composite_node::copy()
4267 return new composite_node(copy_node_list(n), ci, tf, state, div_nest_level);
4270 hunits composite_node::width()
4273 if (tf->get_constant_space(&x))
4276 for (node *tem = n; tem; tem = tem->next)
4279 if (tf->get_bold(&offset))
4281 x += tf->get_track_kern();
4285 node *composite_node::last_char_node()
4290 vunits composite_node::vertical_width()
4293 for (node *tem = n; tem; tem = tem->next)
4294 v += tem->vertical_width();
4298 units composite_node::size()
4300 return tf->get_size().to_units();
4303 hyphenation_type composite_node::get_hyphenation_type()
4305 return HYPHEN_MIDDLE;
4308 void composite_node::asciify(macro *m)
4310 unsigned char c = ci->get_asciify_code();
4312 c = ci->get_ascii_code();
4321 void composite_node::ascii_print(ascii_output_file *ascii)
4323 unsigned char c = ci->get_ascii_code();
4327 ascii->outs(ci->nm.contents());
4331 hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail, int *count)
4334 return new hyphen_list(ci->get_hyphenation_code(), tail);
4337 node *composite_node::add_self(node *nn, hyphen_list **p)
4339 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
4343 nn = nn->add_discretionary_hyphen();
4344 hyphen_list *pp = *p;
4350 tfont *composite_node::get_tfont()
4355 node *reverse_node_list(node *n)
4367 void composite_node::vertical_extent(vunits *minimum, vunits *maximum)
4369 n = reverse_node_list(n);
4370 node_list_vertical_extent(n, minimum, maximum);
4371 n = reverse_node_list(n);
4374 width_list::width_list(hunits w, hunits s)
4375 : width(w), sentence_width(s), next(0)
4379 width_list::width_list(width_list *w)
4380 : width(w->width), sentence_width(w->sentence_width), next(0)
4384 word_space_node::word_space_node(hunits d, color *c, width_list *w, node *x)
4385 : space_node(d, c, x), orig_width(w), unformat(0)
4389 word_space_node::word_space_node(hunits d, int s, color *c, width_list *w,
4390 int flag, statem *st, int pop, node *x)
4391 : space_node(d, s, 0, c, st, pop, x), orig_width(w), unformat(flag)
4395 word_space_node::~word_space_node()
4397 width_list *w = orig_width;
4399 width_list *tmp = w;
4405 node *word_space_node::copy()
4407 assert(orig_width != 0);
4408 width_list *w_old_curr = orig_width;
4409 width_list *w_new_curr = new width_list(w_old_curr);
4410 width_list *w_new = w_new_curr;
4411 w_old_curr = w_old_curr->next;
4412 while (w_old_curr != 0) {
4413 w_new_curr->next = new width_list(w_old_curr);
4414 w_new_curr = w_new_curr->next;
4415 w_old_curr = w_old_curr->next;
4417 return new word_space_node(n, set, col, w_new, unformat, state,
4421 int word_space_node::set_unformat_flag()
4427 void word_space_node::tprint(troff_output_file *out)
4429 out->fill_color(col);
4434 int word_space_node::merge_space(hunits h, hunits sw, hunits ssw)
4437 assert(orig_width != 0);
4438 width_list *w = orig_width;
4439 for (; w->next; w = w->next)
4441 w->next = new width_list(sw, ssw);
4445 unbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x)
4446 : word_space_node(d, c, 0, x)
4450 unbreakable_space_node::unbreakable_space_node(hunits d, int s,
4451 color *c, statem *st, int pop,
4453 : word_space_node(d, s, c, 0, 0, st, pop, x)
4457 node *unbreakable_space_node::copy()
4459 return new unbreakable_space_node(n, set, col, state, div_nest_level);
4462 int unbreakable_space_node::force_tprint()
4467 int unbreakable_space_node::is_tag()
4472 breakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
4473 breakpoint *rest, int)
4478 int unbreakable_space_node::nbreaks()
4483 void unbreakable_space_node::split(int, node **, node **)
4488 int unbreakable_space_node::merge_space(hunits, hunits, hunits)
4497 draw_node::draw_node(char c, hvpair *p, int np, font_size s,
4498 color *gc, color *fc)
4499 : npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4501 point = new hvpair[npoints];
4502 for (int i = 0; i < npoints; i++)
4506 draw_node::draw_node(char c, hvpair *p, int np, font_size s,
4507 color *gc, color *fc, statem *st, int pop)
4508 : node(0, st, pop), npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4510 point = new hvpair[npoints];
4511 for (int i = 0; i < npoints; i++)
4515 int draw_node::same(node *n)
4517 draw_node *nd = (draw_node *)n;
4518 if (code != nd->code || npoints != nd->npoints || sz != nd->sz
4519 || gcol != nd->gcol || fcol != nd->fcol)
4521 for (int i = 0; i < npoints; i++)
4522 if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
4527 const char *draw_node::type()
4532 int draw_node::force_tprint()
4537 int draw_node::is_tag()
4542 draw_node::~draw_node()
4548 hunits draw_node::width()
4551 for (int i = 0; i < npoints; i++)
4556 vunits draw_node::vertical_width()
4561 for (int i = 0; i < npoints; i++)
4566 node *draw_node::copy()
4568 return new draw_node(code, point, npoints, sz, gcol, fcol, state,
4572 void draw_node::tprint(troff_output_file *out)
4574 out->draw(code, point, npoints, sz, gcol, fcol);
4577 /* tprint methods */
4579 void glyph_node::tprint(troff_output_file *out)
4581 tfont *ptf = tf->get_plain();
4583 out->put_char_width(ci, ptf, gcol, fcol, width(), H0);
4586 int bold = tf->get_bold(&offset);
4587 hunits w = ptf->get_width(ci);
4590 int cs = tf->get_constant_space(&x);
4600 k = tf->get_track_kern();
4602 out->put_char(ci, ptf, gcol, fcol);
4605 out->put_char_width(ci, ptf, gcol, fcol, w, k);
4609 void glyph_node::zero_width_tprint(troff_output_file *out)
4611 tfont *ptf = tf->get_plain();
4613 int bold = tf->get_bold(&offset);
4615 int cs = tf->get_constant_space(&x);
4617 x -= ptf->get_width(ci);
4623 out->put_char(ci, ptf, gcol, fcol);
4626 out->put_char(ci, ptf, gcol, fcol);
4627 out->right(-offset);
4633 void break_char_node::tprint(troff_output_file *t)
4638 void break_char_node::zero_width_tprint(troff_output_file *t)
4640 ch->zero_width_tprint(t);
4643 void hline_node::tprint(troff_output_file *out)
4653 hunits w = n->width();
4655 error("horizontal line drawing character must have positive width");
4666 out->right(xx - xx2);
4669 hunits rem = x - w*i;
4671 if (n->overlaps_horizontally()) {
4674 out->right(rem - w);
4685 void vline_node::tprint(troff_output_file *out)
4691 vunits h = n->size();
4692 int overlaps = n->overlaps_vertically();
4697 vunits rem = y - i*h;
4699 out->right(n->width());
4704 n->zero_width_tprint(out);
4708 n->zero_width_tprint(out);
4717 out->down(-h - rem);
4723 vunits rem = y - i*h;
4726 out->right(n->width());
4731 n->zero_width_tprint(out);
4734 n->zero_width_tprint(out);
4743 void zero_width_node::tprint(troff_output_file *out)
4748 n->zero_width_tprint(out);
4751 int hpos = out->get_hpos();
4752 int vpos = out->get_vpos();
4758 out->moveto(hpos, vpos);
4761 void overstrike_node::tprint(troff_output_file *out)
4764 for (node *tem = list; tem; tem = tem->next) {
4765 hunits x = (max_width - tem->width())/2;
4766 out->right(x - pos);
4768 tem->zero_width_tprint(out);
4770 out->right(max_width - pos);
4773 void bracket_node::tprint(troff_output_file *out)
4779 for (tem = list; tem; tem = tem->next)
4781 vunits h = list->size();
4782 vunits totalh = h*npieces;
4783 vunits y = (totalh - h)/2;
4785 for (tem = list; tem; tem = tem->next) {
4786 tem->zero_width_tprint(out);
4789 out->right(max_width);
4790 out->down(totalh - y);
4793 void node::tprint(troff_output_file *)
4797 void node::zero_width_tprint(troff_output_file *out)
4799 int hpos = out->get_hpos();
4800 int vpos = out->get_vpos();
4802 out->moveto(hpos, vpos);
4805 void space_node::tprint(troff_output_file *out)
4807 out->fill_color(col);
4811 void hmotion_node::tprint(troff_output_file *out)
4813 out->fill_color(col);
4817 void space_char_hmotion_node::tprint(troff_output_file *out)
4819 out->fill_color(col);
4821 // we emit the space width as a negative glyph index
4825 out->put(-n.to_units());
4831 void vmotion_node::tprint(troff_output_file *out)
4833 out->fill_color(col);
4837 void kern_pair_node::tprint(troff_output_file *out)
4844 static void tprint_reverse_node_list(troff_output_file *out, node *n)
4848 tprint_reverse_node_list(out, n->next);
4852 void dbreak_node::tprint(troff_output_file *out)
4854 tprint_reverse_node_list(out, none);
4857 void composite_node::tprint(troff_output_file *out)
4860 int is_bold = tf->get_bold(&bold_offset);
4861 hunits track_kern = tf->get_track_kern();
4862 hunits constant_space;
4863 int is_constant_spaced = tf->get_constant_space(&constant_space);
4865 if (is_constant_spaced) {
4867 for (node *tem = n; tem; tem = tem->next)
4876 int hpos = out->get_hpos();
4877 int vpos = out->get_vpos();
4878 tprint_reverse_node_list(out, n);
4879 out->moveto(hpos, vpos);
4880 out->right(bold_offset);
4882 tprint_reverse_node_list(out, n);
4883 if (is_constant_spaced)
4886 out->right(track_kern);
4889 node *make_composite_node(charinfo *s, environment *env)
4891 int fontno = env_definite_font(env);
4893 error("no current font");
4896 assert(fontno < font_table_size && font_table[fontno] != 0);
4897 node *n = charinfo_to_node_list(s, env);
4898 font_size fs = env->get_font_size();
4899 int char_height = env->get_char_height();
4900 int char_slant = env->get_char_slant();
4901 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
4903 if (env->is_composite())
4904 tf = tf->get_plain();
4905 return new composite_node(n, s, tf, 0, 0, 0);
4908 node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
4910 int fontno = env_definite_font(env);
4912 error("no current font");
4915 assert(fontno < font_table_size && font_table[fontno] != 0);
4917 int found = font_table[fontno]->contains(s);
4919 macro *mac = s->get_macro();
4920 if (mac && s->is_fallback())
4921 return make_composite_node(s, env);
4922 if (s->numbered()) {
4923 if (!no_error_message)
4924 warning(WARN_CHAR, "can't find numbered character %1",
4928 special_font_list *sf = font_table[fontno]->sf;
4929 while (sf != 0 && !found) {
4932 found = font_table[fn]->contains(s);
4936 symbol f = font_table[fontno]->get_name();
4937 string gl(f.contents());
4939 gl += s->nm.contents();
4941 charinfo *ci = get_charinfo(symbol(gl.contents()));
4942 if (ci && ci->get_macro())
4943 return make_composite_node(ci, env);
4946 sf = global_special_fonts;
4947 while (sf != 0 && !found) {
4950 found = font_table[fn]->contains(s);
4955 if (mac && s->is_special())
4956 return make_composite_node(s, env);
4958 for (fn = 0; fn < font_table_size; fn++)
4960 && font_table[fn]->is_special()
4961 && font_table[fn]->contains(s)) {
4967 if (!no_error_message && s->first_time_not_found()) {
4968 unsigned char input_code = s->get_ascii_code();
4969 if (input_code != 0) {
4970 if (csgraph(input_code))
4971 warning(WARN_CHAR, "can't find character `%1'", input_code);
4973 warning(WARN_CHAR, "can't find character with input code %1",
4976 else if (s->nm.contents()) {
4977 const char *nm = s->nm.contents();
4978 const char *backslash = (nm[1] == 0) ? "\\" : "";
4979 warning(WARN_CHAR, "can't find special character `%1%2'",
4986 font_size fs = env->get_font_size();
4987 int char_height = env->get_char_height();
4988 int char_slant = env->get_char_slant();
4989 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
4990 if (env->is_composite())
4991 tf = tf->get_plain();
4992 color *gcol = env->get_glyph_color();
4993 color *fcol = env->get_fill_color();
4994 return new glyph_node(s, tf, gcol, fcol, 0, 0);
4997 node *make_node(charinfo *ci, environment *env)
4999 switch (ci->get_special_translation()) {
5000 case charinfo::TRANSLATE_SPACE:
5001 return new space_char_hmotion_node(env->get_space_width(),
5002 env->get_fill_color());
5003 case charinfo::TRANSLATE_STRETCHABLE_SPACE:
5004 return new unbreakable_space_node(env->get_space_width(),
5005 env->get_fill_color());
5006 case charinfo::TRANSLATE_DUMMY:
5007 return new dummy_node;
5008 case charinfo::TRANSLATE_HYPHEN_INDICATOR:
5009 error("translation to \\%% ignored in this context");
5012 charinfo *tem = ci->get_translation();
5015 macro *mac = ci->get_macro();
5016 if (mac && ci->is_normal())
5017 return make_composite_node(ci, env);
5019 return make_glyph_node(ci, env);
5022 int character_exists(charinfo *ci, environment *env)
5024 if (ci->get_special_translation() != charinfo::TRANSLATE_NONE)
5026 charinfo *tem = ci->get_translation();
5029 if (ci->get_macro())
5031 node *nd = make_glyph_node(ci, env, 1);
5039 node *node::add_char(charinfo *ci, environment *env,
5040 hunits *widthp, int *spacep, node **glyph_comp_np)
5043 switch (ci->get_special_translation()) {
5044 case charinfo::TRANSLATE_SPACE:
5045 res = new space_char_hmotion_node(env->get_space_width(),
5046 env->get_fill_color(), this);
5047 *widthp += res->width();
5049 case charinfo::TRANSLATE_STRETCHABLE_SPACE:
5050 res = new unbreakable_space_node(env->get_space_width(),
5051 env->get_fill_color(), this);
5052 res->freeze_space();
5053 *widthp += res->width();
5054 *spacep += res->nspaces();
5056 case charinfo::TRANSLATE_DUMMY:
5057 return new dummy_node(this);
5058 case charinfo::TRANSLATE_HYPHEN_INDICATOR:
5059 return add_discretionary_hyphen();
5061 charinfo *tem = ci->get_translation();
5064 macro *mac = ci->get_macro();
5065 if (mac && ci->is_normal()) {
5066 res = make_composite_node(ci, env);
5069 *widthp += res->width();
5071 *glyph_comp_np = res;
5075 *glyph_comp_np = res;
5080 node *gn = make_glyph_node(ci, env);
5084 hunits old_width = width();
5085 node *p = gn->merge_self(this);
5087 *widthp += gn->width();
5092 *widthp += p->width() - old_width;
5096 *glyph_comp_np = res;
5100 if (ci->can_break_before())
5101 break_code = CAN_BREAK_BEFORE;
5102 if (ci->can_break_after())
5103 break_code |= CAN_BREAK_AFTER;
5104 if (ci->ignore_hcodes())
5105 break_code |= IGNORE_HCODES;
5106 if (ci->prohibit_break_before())
5107 break_code = PROHIBIT_BREAK_BEFORE;
5108 if (ci->prohibit_break_after())
5109 break_code |= PROHIBIT_BREAK_AFTER;
5110 if (ci->inter_char_space())
5111 break_code |= INTER_CHAR_SPACE;
5113 node *next1 = res->next;
5115 res = new break_char_node(res, break_code, get_break_code(),
5116 env->get_fill_color(), next1);
5124 int same_node(node *n1, node *n2)
5128 return n1->type() == n2->type() && n1->same(n2);
5136 int same_node_list(node *n1, node *n2)
5139 if (n1->type() != n2->type() || !n1->same(n2))
5147 int extra_size_node::same(node *nd)
5149 return n == ((extra_size_node *)nd)->n;
5152 const char *extra_size_node::type()
5154 return "extra_size_node";
5157 int extra_size_node::force_tprint()
5162 int extra_size_node::is_tag()
5167 int vertical_size_node::same(node *nd)
5169 return n == ((vertical_size_node *)nd)->n;
5172 const char *vertical_size_node::type()
5174 return "vertical_size_node";
5177 int vertical_size_node::set_unformat_flag()
5182 int vertical_size_node::force_tprint()
5187 int vertical_size_node::is_tag()
5192 int hmotion_node::same(node *nd)
5194 return n == ((hmotion_node *)nd)->n
5195 && col == ((hmotion_node *)nd)->col;
5198 const char *hmotion_node::type()
5200 return "hmotion_node";
5203 int hmotion_node::set_unformat_flag()
5209 int hmotion_node::force_tprint()
5214 int hmotion_node::is_tag()
5219 node *hmotion_node::add_self(node *nd, hyphen_list **p)
5222 hyphen_list *pp = *p;
5228 hyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail, int *)
5230 return new hyphen_list(0, tail);
5233 int space_char_hmotion_node::same(node *nd)
5235 return n == ((space_char_hmotion_node *)nd)->n
5236 && col == ((space_char_hmotion_node *)nd)->col;
5239 const char *space_char_hmotion_node::type()
5241 return "space_char_hmotion_node";
5244 int space_char_hmotion_node::force_tprint()
5249 int space_char_hmotion_node::is_tag()
5254 node *space_char_hmotion_node::add_self(node *nd, hyphen_list **p)
5257 hyphen_list *pp = *p;
5263 hyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail,
5266 return new hyphen_list(0, tail);
5269 int vmotion_node::same(node *nd)
5271 return n == ((vmotion_node *)nd)->n
5272 && col == ((vmotion_node *)nd)->col;
5275 const char *vmotion_node::type()
5277 return "vmotion_node";
5280 int vmotion_node::force_tprint()
5285 int vmotion_node::is_tag()
5290 int hline_node::same(node *nd)
5292 return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
5295 const char *hline_node::type()
5297 return "hline_node";
5300 int hline_node::force_tprint()
5305 int hline_node::is_tag()
5310 int vline_node::same(node *nd)
5312 return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
5315 const char *vline_node::type()
5317 return "vline_node";
5320 int vline_node::force_tprint()
5325 int vline_node::is_tag()
5330 int dummy_node::same(node * /*nd*/)
5335 const char *dummy_node::type()
5337 return "dummy_node";
5340 int dummy_node::force_tprint()
5345 int dummy_node::is_tag()
5350 int transparent_dummy_node::same(node * /*nd*/)
5355 const char *transparent_dummy_node::type()
5357 return "transparent_dummy_node";
5360 int transparent_dummy_node::force_tprint()
5365 int transparent_dummy_node::is_tag()
5370 int transparent_dummy_node::ends_sentence()
5375 int zero_width_node::same(node *nd)
5377 return same_node_list(n, ((zero_width_node *)nd)->n);
5380 const char *zero_width_node::type()
5382 return "zero_width_node";
5385 int zero_width_node::force_tprint()
5390 int zero_width_node::is_tag()
5395 int italic_corrected_node::same(node *nd)
5397 return (x == ((italic_corrected_node *)nd)->x
5398 && same_node(n, ((italic_corrected_node *)nd)->n));
5401 const char *italic_corrected_node::type()
5403 return "italic_corrected_node";
5406 int italic_corrected_node::force_tprint()
5411 int italic_corrected_node::is_tag()
5416 left_italic_corrected_node::left_italic_corrected_node(node *xx)
5421 left_italic_corrected_node::left_italic_corrected_node(statem *s, int pop,
5423 : node(xx, s, pop), n(0)
5427 left_italic_corrected_node::~left_italic_corrected_node()
5432 node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn)
5435 hunits lic = gn->left_italic_correction();
5436 if (!lic.is_zero()) {
5443 node *nd = n->merge_glyph_node(gn);
5446 x = n->left_italic_correction();
5453 node *left_italic_corrected_node::copy()
5455 left_italic_corrected_node *nd =
5456 new left_italic_corrected_node(state, div_nest_level);
5464 void left_italic_corrected_node::tprint(troff_output_file *out)
5472 const char *left_italic_corrected_node::type()
5474 return "left_italic_corrected_node";
5477 int left_italic_corrected_node::force_tprint()
5482 int left_italic_corrected_node::is_tag()
5487 int left_italic_corrected_node::same(node *nd)
5489 return (x == ((left_italic_corrected_node *)nd)->x
5490 && same_node(n, ((left_italic_corrected_node *)nd)->n));
5493 void left_italic_corrected_node::ascii_print(ascii_output_file *out)
5496 n->ascii_print(out);
5499 hunits left_italic_corrected_node::width()
5501 return n ? n->width() + x : H0;
5504 void left_italic_corrected_node::vertical_extent(vunits *minimum,
5508 n->vertical_extent(minimum, maximum);
5510 node::vertical_extent(minimum, maximum);
5513 hunits left_italic_corrected_node::skew()
5515 return n ? n->skew() + x/2 : H0;
5518 hunits left_italic_corrected_node::subscript_correction()
5520 return n ? n->subscript_correction() : H0;
5523 hunits left_italic_corrected_node::italic_correction()
5525 return n ? n->italic_correction() : H0;
5528 int left_italic_corrected_node::ends_sentence()
5530 return n ? n->ends_sentence() : 0;
5533 int left_italic_corrected_node::overlaps_horizontally()
5535 return n ? n->overlaps_horizontally() : 0;
5538 int left_italic_corrected_node::overlaps_vertically()
5540 return n ? n->overlaps_vertically() : 0;
5543 node *left_italic_corrected_node::last_char_node()
5545 return n ? n->last_char_node() : 0;
5548 tfont *left_italic_corrected_node::get_tfont()
5550 return n ? n->get_tfont() : 0;
5553 hyphenation_type left_italic_corrected_node::get_hyphenation_type()
5556 return n->get_hyphenation_type();
5558 return HYPHEN_MIDDLE;
5561 hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail,
5564 return n ? n->get_hyphen_list(tail, count) : tail;
5567 node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p)
5570 nd = new left_italic_corrected_node(state, div_nest_level, nd);
5571 nd = n->add_self(nd, p);
5582 int left_italic_corrected_node::character_type()
5584 return n ? n->character_type() : 0;
5587 int overstrike_node::same(node *nd)
5589 return same_node_list(list, ((overstrike_node *)nd)->list);
5592 const char *overstrike_node::type()
5594 return "overstrike_node";
5597 int overstrike_node::force_tprint()
5602 int overstrike_node::is_tag()
5607 node *overstrike_node::add_self(node *n, hyphen_list **p)
5610 hyphen_list *pp = *p;
5616 hyphen_list *overstrike_node::get_hyphen_list(hyphen_list *tail, int *)
5618 return new hyphen_list(0, tail);
5621 int bracket_node::same(node *nd)
5623 return same_node_list(list, ((bracket_node *)nd)->list);
5626 const char *bracket_node::type()
5628 return "bracket_node";
5631 int bracket_node::force_tprint()
5636 int bracket_node::is_tag()
5641 int composite_node::same(node *nd)
5643 return ci == ((composite_node *)nd)->ci
5644 && same_node_list(n, ((composite_node *)nd)->n);
5647 const char *composite_node::type()
5649 return "composite_node";
5652 int composite_node::force_tprint()
5657 int composite_node::is_tag()
5662 int glyph_node::same(node *nd)
5664 return ci == ((glyph_node *)nd)->ci
5665 && tf == ((glyph_node *)nd)->tf
5666 && gcol == ((glyph_node *)nd)->gcol
5667 && fcol == ((glyph_node *)nd)->fcol;
5670 const char *glyph_node::type()
5672 return "glyph_node";
5675 int glyph_node::force_tprint()
5680 int glyph_node::is_tag()
5685 int ligature_node::same(node *nd)
5687 return (same_node(n1, ((ligature_node *)nd)->n1)
5688 && same_node(n2, ((ligature_node *)nd)->n2)
5689 && glyph_node::same(nd));
5692 const char *ligature_node::type()
5694 return "ligature_node";
5697 int ligature_node::force_tprint()
5702 int ligature_node::is_tag()
5707 int kern_pair_node::same(node *nd)
5709 return (amount == ((kern_pair_node *)nd)->amount
5710 && same_node(n1, ((kern_pair_node *)nd)->n1)
5711 && same_node(n2, ((kern_pair_node *)nd)->n2));
5714 const char *kern_pair_node::type()
5716 return "kern_pair_node";
5719 int kern_pair_node::force_tprint()
5724 int kern_pair_node::is_tag()
5729 int dbreak_node::same(node *nd)
5731 return (same_node_list(none, ((dbreak_node *)nd)->none)
5732 && same_node_list(pre, ((dbreak_node *)nd)->pre)
5733 && same_node_list(post, ((dbreak_node *)nd)->post));
5736 const char *dbreak_node::type()
5738 return "dbreak_node";
5741 int dbreak_node::force_tprint()
5746 int dbreak_node::is_tag()
5751 int break_char_node::same(node *nd)
5753 return break_code == ((break_char_node *)nd)->break_code
5754 && col == ((break_char_node *)nd)->col
5755 && same_node(ch, ((break_char_node *)nd)->ch);
5758 const char *break_char_node::type()
5760 return "break_char_node";
5763 int break_char_node::force_tprint()
5768 int break_char_node::is_tag()
5773 int break_char_node::get_break_code()
5778 int line_start_node::same(node * /*nd*/)
5783 const char *line_start_node::type()
5785 return "line_start_node";
5788 int line_start_node::force_tprint()
5793 int line_start_node::is_tag()
5798 int space_node::same(node *nd)
5800 return n == ((space_node *)nd)->n
5801 && set == ((space_node *)nd)->set
5802 && col == ((space_node *)nd)->col;
5805 const char *space_node::type()
5807 return "space_node";
5810 int word_space_node::same(node *nd)
5812 return n == ((word_space_node *)nd)->n
5813 && set == ((word_space_node *)nd)->set
5814 && col == ((word_space_node *)nd)->col;
5817 const char *word_space_node::type()
5819 return "word_space_node";
5822 int word_space_node::force_tprint()
5827 int word_space_node::is_tag()
5832 void unbreakable_space_node::tprint(troff_output_file *out)
5834 out->fill_color(col);
5836 // we emit the space width as a negative glyph index
5840 out->put(-n.to_units());
5846 int unbreakable_space_node::same(node *nd)
5848 return n == ((unbreakable_space_node *)nd)->n
5849 && set == ((unbreakable_space_node *)nd)->set
5850 && col == ((unbreakable_space_node *)nd)->col;
5853 const char *unbreakable_space_node::type()
5855 return "unbreakable_space_node";
5858 node *unbreakable_space_node::add_self(node *nd, hyphen_list **p)
5861 hyphen_list *pp = *p;
5867 hyphen_list *unbreakable_space_node::get_hyphen_list(hyphen_list *tail, int *)
5869 return new hyphen_list(0, tail);
5872 int diverted_space_node::same(node *nd)
5874 return n == ((diverted_space_node *)nd)->n;
5877 const char *diverted_space_node::type()
5879 return "diverted_space_node";
5882 int diverted_space_node::force_tprint()
5887 int diverted_space_node::is_tag()
5892 int diverted_copy_file_node::same(node *nd)
5894 return filename == ((diverted_copy_file_node *)nd)->filename;
5897 const char *diverted_copy_file_node::type()
5899 return "diverted_copy_file_node";
5902 int diverted_copy_file_node::force_tprint()
5907 int diverted_copy_file_node::is_tag()
5912 // Grow the font_table so that its size is > n.
5914 static void grow_font_table(int n)
5916 assert(n >= font_table_size);
5917 font_info **old_font_table = font_table;
5918 int old_font_table_size = font_table_size;
5919 font_table_size = font_table_size ? (font_table_size*3)/2 : 10;
5920 if (font_table_size <= n)
5921 font_table_size = n + 10;
5922 font_table = new font_info *[font_table_size];
5923 if (old_font_table_size)
5924 memcpy(font_table, old_font_table,
5925 old_font_table_size*sizeof(font_info *));
5926 a_delete old_font_table;
5927 for (int i = old_font_table_size; i < font_table_size; i++)
5931 dictionary font_translation_dictionary(17);
5933 static symbol get_font_translation(symbol nm)
5935 void *p = font_translation_dictionary.lookup(nm);
5936 return p ? symbol((char *)p) : nm;
5939 dictionary font_dictionary(50);
5941 static int mount_font_no_translate(int n, symbol name, symbol external_name,
5945 // We store the address of this char in font_dictionary to indicate
5946 // that we've previously tried to mount the font and failed.
5949 void *p = font_dictionary.lookup(external_name);
5952 fm = font::load_font(external_name.contents(), ¬_found, check_only);
5957 warning(WARN_FONT, "can't find font `%1'", external_name.contents());
5958 (void)font_dictionary.lookup(external_name, &a_char);
5961 (void)font_dictionary.lookup(name, fm);
5963 else if (p == &a_char) {
5965 error("invalid font `%1'", external_name.contents());
5973 if (n >= font_table_size) {
5974 if (n - font_table_size > 1000) {
5975 error("font position too much larger than first unused position");
5980 else if (font_table[n] != 0)
5981 delete font_table[n];
5982 font_table[n] = new font_info(name, n, external_name, fm);
5983 font_family::invalidate_fontno(n);
5987 int mount_font(int n, symbol name, symbol external_name)
5990 name = get_font_translation(name);
5991 if (external_name.is_null())
5992 external_name = name;
5994 external_name = get_font_translation(external_name);
5995 return mount_font_no_translate(n, name, external_name);
5998 int check_font(symbol fam, symbol name)
6000 if (check_style(name))
6001 name = concat(fam, name);
6002 return mount_font_no_translate(0, name, name, 1);
6005 int check_style(symbol s)
6007 int i = symbol_fontno(s);
6008 return i < 0 ? 0 : font_table[i]->is_style();
6011 void mount_style(int n, symbol name)
6014 if (n >= font_table_size) {
6015 if (n - font_table_size > 1000) {
6016 error("font position too much larger than first unused position");
6021 else if (font_table[n] != 0)
6022 delete font_table[n];
6023 font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0);
6024 font_family::invalidate_fontno(n);
6027 /* global functions */
6029 void font_translate()
6031 symbol from = get_name(1);
6032 if (!from.is_null()) {
6033 symbol to = get_name();
6034 if (to.is_null() || from == to)
6035 font_translation_dictionary.remove(from);
6037 (void)font_translation_dictionary.lookup(from, (void *)to.contents());
6042 void font_position()
6045 if (get_integer(&n)) {
6047 error("negative font position");
6049 symbol internal_name = get_name(1);
6050 if (!internal_name.is_null()) {
6051 symbol external_name = get_long_name();
6052 mount_font(n, internal_name, external_name); // ignore error
6059 font_family::font_family(symbol s)
6060 : map_size(10), nm(s)
6062 map = new int[map_size];
6063 for (int i = 0; i < map_size; i++)
6067 font_family::~font_family()
6072 int font_family::make_definite(int i)
6075 if (i < map_size && map[i] >= 0)
6078 if (i < font_table_size && font_table[i] != 0) {
6079 if (i >= map_size) {
6080 int old_map_size = map_size;
6086 map = new int[map_size];
6087 memcpy(map, old_map, old_map_size*sizeof(int));
6089 for (int j = old_map_size; j < map_size; j++)
6092 if (font_table[i]->is_style()) {
6093 symbol sty = font_table[i]->get_name();
6094 symbol f = concat(nm, sty);
6096 // don't use symbol_fontno, because that might return a style
6097 // and because we don't want to translate the name
6098 for (n = 0; n < font_table_size; n++)
6099 if (font_table[n] != 0 && font_table[n]->is_named(f)
6100 && !font_table[n]->is_style())
6102 if (n >= font_table_size) {
6103 n = next_available_font_position();
6104 if (!mount_font_no_translate(n, f, f))
6120 dictionary family_dictionary(5);
6122 font_family *lookup_family(symbol nm)
6124 font_family *f = (font_family *)family_dictionary.lookup(nm);
6126 f = new font_family(nm);
6127 (void)family_dictionary.lookup(nm, f);
6132 void font_family::invalidate_fontno(int n)
6134 assert(n >= 0 && n < font_table_size);
6135 dictionary_iterator iter(family_dictionary);
6138 while (iter.get(&nam, (void **)&fam)) {
6139 int mapsize = fam->map_size;
6142 for (int i = 0; i < mapsize; i++)
6143 if (fam->map[i] == n)
6151 if (get_integer(&n)) {
6153 error("negative font position");
6155 symbol internal_name = get_name(1);
6156 if (!internal_name.is_null())
6157 mount_style(n, internal_name);
6163 static int get_fontno()
6167 if (tok.delimiter()) {
6168 symbol s = get_name(1);
6170 n = symbol_fontno(s);
6172 n = next_available_font_position();
6173 if (!mount_font(n, s))
6176 return curenv->get_family()->make_definite(n);
6179 else if (get_integer(&n)) {
6180 if (n < 0 || n >= font_table_size || font_table[n] == 0)
6181 error("bad font number");
6183 return curenv->get_family()->make_definite(n);
6188 static int underline_fontno = 2;
6190 void underline_font()
6192 int n = get_fontno();
6194 underline_fontno = n;
6198 int get_underline_fontno()
6200 return underline_fontno;
6203 void define_font_special_character()
6205 int n = get_fontno();
6210 symbol f = font_table[n]->get_name();
6211 do_define_character(CHAR_FONT_SPECIAL, f.contents());
6214 void remove_font_special_character()
6216 int n = get_fontno();
6221 symbol f = font_table[n]->get_name();
6222 while (!tok.newline() && !tok.eof()) {
6223 if (!tok.space() && !tok.tab()) {
6224 charinfo *s = tok.get_char(1);
6225 string gl(f.contents());
6227 gl += s->nm.contents();
6229 charinfo *ci = get_charinfo(symbol(gl.contents()));
6232 macro *m = ci->set_macro(0);
6241 static void read_special_fonts(special_font_list **sp)
6243 special_font_list *s = *sp;
6246 special_font_list *tem = s;
6250 special_font_list **p = sp;
6252 int i = get_fontno();
6254 special_font_list *tem = new special_font_list;
6263 void font_special_request()
6265 int n = get_fontno();
6267 read_special_fonts(&font_table[n]->sf);
6271 void special_request()
6273 read_special_fonts(&global_special_fonts);
6277 void font_zoom_request()
6279 int n = get_fontno();
6281 if (font_table[n]->is_style())
6282 warning(WARN_FONT, "can't set zoom factor for a style");
6285 if (has_arg() && get_integer(&zoom)) {
6287 warning(WARN_FONT, "can't use negative zoom factor");
6289 font_table[n]->set_zoom(zoom);
6292 font_table[n]->set_zoom(0);
6298 int next_available_font_position()
6301 for (i = 1; i < font_table_size && font_table[i] != 0; i++)
6306 int symbol_fontno(symbol s)
6308 s = get_font_translation(s);
6309 for (int i = 0; i < font_table_size; i++)
6310 if (font_table[i] != 0 && font_table[i]->is_named(s))
6315 int is_good_fontno(int n)
6317 return n >= 0 && n < font_table_size && font_table[n] != 0;
6320 int get_bold_fontno(int n)
6322 if (n >= 0 && n < font_table_size && font_table[n] != 0) {
6324 if (font_table[n]->get_bold(&offset))
6325 return offset.to_units() + 1;
6333 hunits env_digit_width(environment *env)
6335 node *n = make_glyph_node(charset_table['0'], env);
6337 hunits x = n->width();
6345 hunits env_space_width(environment *env)
6347 int fn = env_definite_font(env);
6348 font_size fs = env->get_font_size();
6349 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6350 return scale(fs.to_units()/3, env->get_space_size(), 12);
6352 return font_table[fn]->get_space_width(fs, env->get_space_size());
6355 hunits env_sentence_space_width(environment *env)
6357 int fn = env_definite_font(env);
6358 font_size fs = env->get_font_size();
6359 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6360 return scale(fs.to_units()/3, env->get_sentence_space_size(), 12);
6362 return font_table[fn]->get_space_width(fs, env->get_sentence_space_size());
6365 hunits env_half_narrow_space_width(environment *env)
6367 int fn = env_definite_font(env);
6368 font_size fs = env->get_font_size();
6369 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6372 return font_table[fn]->get_half_narrow_space_width(fs);
6375 hunits env_narrow_space_width(environment *env)
6377 int fn = env_definite_font(env);
6378 font_size fs = env->get_font_size();
6379 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6382 return font_table[fn]->get_narrow_space_width(fs);
6387 int n = get_fontno();
6390 if (tok.delimiter()) {
6391 int f = get_fontno();
6394 if (has_arg() && get_number(&offset, 'u') && offset >= 1)
6395 font_table[f]->set_conditional_bold(n, hunits(offset - 1));
6397 font_table[f]->conditional_unbold(n);
6402 if (get_number(&offset, 'u') && offset >= 1)
6403 font_table[n]->set_bold(hunits(offset - 1));
6405 font_table[n]->unbold();
6409 font_table[n]->unbold();
6414 track_kerning_function::track_kerning_function() : non_zero(0)
6418 track_kerning_function::track_kerning_function(int min_s, hunits min_a,
6419 int max_s, hunits max_a)
6420 : non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s),
6425 int track_kerning_function::operator==(const track_kerning_function &tk)
6429 && min_size == tk.min_size
6430 && min_amount == tk.min_amount
6431 && max_size == tk.max_size
6432 && max_amount == tk.max_amount);
6434 return !tk.non_zero;
6437 int track_kerning_function::operator!=(const track_kerning_function &tk)
6440 return (!tk.non_zero
6441 || min_size != tk.min_size
6442 || min_amount != tk.min_amount
6443 || max_size != tk.max_size
6444 || max_amount != tk.max_amount);
6449 hunits track_kerning_function::compute(int size)
6452 if (max_size <= min_size)
6454 else if (size <= min_size)
6456 else if (size >= max_size)
6459 return (scale(max_amount, size - min_size, max_size - min_size)
6460 + scale(min_amount, max_size - size, max_size - min_size));
6468 int n = get_fontno();
6471 hunits min_a, max_a;
6473 && get_number(&min_s, 'z')
6474 && get_hunits(&min_a, 'p')
6475 && get_number(&max_s, 'z')
6476 && get_hunits(&max_a, 'p')) {
6477 track_kerning_function tk(min_s, min_a, max_s, max_a);
6478 font_table[n]->set_track_kern(tk);
6481 track_kerning_function tk;
6482 font_table[n]->set_track_kern(tk);
6488 void constant_space()
6490 int n = get_fontno();
6493 if (!has_arg() || !get_integer(&x))
6494 font_table[n]->set_constant_space(CONSTANT_SPACE_NONE);
6496 if (!has_arg() || !get_number(&y, 'z'))
6497 font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x);
6499 font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE,
6511 if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2)
6512 global_ligature_mode = lig;
6514 global_ligature_mode = 1;
6521 if (has_arg() && get_integer(&k))
6522 global_kern_mode = k != 0;
6524 global_kern_mode = 1;
6528 void set_soft_hyphen_char()
6530 soft_hyphen_char = get_optional_char();
6531 if (!soft_hyphen_char)
6532 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
6538 if (suppress_output_flag)
6539 the_output = new suppress_output_file;
6540 else if (ascii_output_flag)
6541 the_output = new ascii_output_file;
6543 the_output = new troff_output_file;
6546 class next_available_font_position_reg : public reg {
6548 const char *get_string();
6551 const char *next_available_font_position_reg::get_string()
6553 return i_to_a(next_available_font_position());
6556 class printing_reg : public reg {
6558 const char *get_string();
6561 const char *printing_reg::get_string()
6564 return the_output->is_printing() ? "1" : "0";
6569 void init_node_requests()
6571 init_request("bd", bold_font);
6572 init_request("cs", constant_space);
6573 init_request("fp", font_position);
6574 init_request("fschar", define_font_special_character);
6575 init_request("fspecial", font_special_request);
6576 init_request("fzoom", font_zoom_request);
6577 init_request("ftr", font_translate);
6578 init_request("kern", kern_request);
6579 init_request("lg", ligature);
6580 init_request("rfschar", remove_font_special_character);
6581 init_request("shc", set_soft_hyphen_char);
6582 init_request("special", special_request);
6583 init_request("sty", style);
6584 init_request("tkf", track_kern);
6585 init_request("uf", underline_font);
6586 number_reg_dictionary.define(".fp", new next_available_font_position_reg);
6587 number_reg_dictionary.define(".kern",
6588 new constant_int_reg(&global_kern_mode));
6589 number_reg_dictionary.define(".lg",
6590 new constant_int_reg(&global_ligature_mode));
6591 number_reg_dictionary.define(".P", new printing_reg);
6592 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);