2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005,
4 Free Software Foundation, Inc.
5 Written by James Clark (jjc@jclark.com)
7 This file is part of groff.
9 groff is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 groff is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 extern int debug_state;
30 #include "dictionary.h"
32 #include "stringclass.h"
51 #else /* not _POSIX_VERSION */
53 /* traditional Unix */
55 #define WIFEXITED(s) (((s) & 0377) == 0)
56 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
57 #define WTERMSIG(s) ((s) & 0177)
58 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
59 #define WSTOPSIG(s) (((s) >> 8) & 0377)
60 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
62 #endif /* not _POSIX_VERSION */
64 // declarations to avoid friend name injections
67 tfont *make_tfont(tfont_spec &);
71 * how many boundaries of images have been written? Useful for
76 static int suppress_start_page = 0;
80 symbol HYPHEN_SYMBOL("hy");
82 // Character used when a hyphen is inserted at a line break.
83 static charinfo *soft_hyphen_char;
85 enum constant_space_type {
87 CONSTANT_SPACE_RELATIVE,
88 CONSTANT_SPACE_ABSOLUTE
91 struct special_font_list {
93 special_font_list *next;
96 special_font_list *global_special_fonts;
97 static int global_ligature_mode = 1;
98 static int global_kern_mode = 1;
100 class track_kerning_function {
107 track_kerning_function();
108 track_kerning_function(units, hunits, units, hunits);
109 int operator==(const track_kerning_function &);
110 int operator!=(const track_kerning_function &);
111 hunits compute(int point_size);
114 // embolden fontno when this is the current font
116 struct conditional_bold {
117 conditional_bold *next;
120 conditional_bold(int, hunits, conditional_bold * = 0);
129 symbol internal_name;
130 symbol external_name;
134 track_kerning_function track_kern;
135 constant_space_type is_constant_spaced;
136 units constant_space;
137 int last_ligature_mode;
139 conditional_bold *cond_bold_list;
142 special_font_list *sf;
143 font_info(symbol, int, symbol, font *);
144 int contains(charinfo *);
145 void set_bold(hunits);
147 void set_conditional_bold(int, hunits);
148 void conditional_unbold(int);
149 void set_track_kern(track_kerning_function &);
150 void set_constant_space(constant_space_type, units = 0);
151 int is_named(symbol);
153 tfont *get_tfont(font_size, int, int, int);
154 hunits get_space_width(font_size, int);
155 hunits get_narrow_space_width(font_size);
156 hunits get_half_narrow_space_width(font_size);
157 int get_bold(hunits *);
162 friend symbol get_font_name(int, environment *);
163 friend symbol get_style_name(int);
173 char is_constant_spaced;
177 hunits track_kern; // add this to the width
178 hunits constant_space_width;
182 tfont_spec(symbol, int, font *, font_size, int, int);
183 tfont_spec(const tfont_spec &spec) { *this = spec; }
185 int operator==(const tfont_spec &);
186 friend tfont *font_info::get_tfont(font_size fs, int, int, int);
189 class tfont : public tfont_spec {
190 static tfont *tfont_list;
192 tfont *plain_version;
195 int contains(charinfo *);
196 hunits get_width(charinfo *c);
197 int get_bold(hunits *);
198 int get_constant_space(hunits *);
199 hunits get_track_kern();
201 font_size get_size();
204 charinfo *get_lig(charinfo *c1, charinfo *c2);
205 int get_kern(charinfo *c1, charinfo *c2, hunits *res);
206 int get_input_position();
207 int get_character_type(charinfo *);
210 vunits get_char_height(charinfo *);
211 vunits get_char_depth(charinfo *);
212 hunits get_char_skew(charinfo *);
213 hunits get_italic_correction(charinfo *);
214 hunits get_left_italic_correction(charinfo *);
215 hunits get_subscript_correction(charinfo *);
216 friend tfont *make_tfont(tfont_spec &);
219 inline int env_definite_font(environment *env)
221 return env->get_family()->make_definite(env->get_font());
224 /* font_info functions */
226 static font_info **font_table = 0;
227 static int font_table_size = 0;
229 font_info::font_info(symbol nm, int n, symbol enm, font *f)
230 : last_tfont(0), number(n), last_size(0),
231 internal_name(nm), external_name(enm), fm(f),
232 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1),
233 last_kern_mode(1), cond_bold_list(0), sf(0)
237 inline int font_info::contains(charinfo *ci)
239 return fm != 0 && fm->contains(ci->as_glyph());
242 inline int font_info::is_special()
244 return fm != 0 && fm->is_special();
247 inline int font_info::is_style()
252 void font_info::set_zoom(int zoom)
258 inline int font_info::get_zoom()
262 return fm->get_zoom();
265 tfont *make_tfont(tfont_spec &spec)
267 for (tfont *p = tfont::tfont_list; p; p = p->next)
270 return new tfont(spec);
273 int env_get_zoom(environment *env)
275 int fontno = env->get_family()->make_definite(env->get_font());
276 return font_table[fontno]->get_zoom();
279 // this is the current_font, fontno is where we found the character,
280 // presumably a special font
282 tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
284 if (last_tfont == 0 || fs != last_size
285 || height != last_height || slant != last_slant
286 || global_ligature_mode != last_ligature_mode
287 || global_kern_mode != last_kern_mode
288 || fontno != number) {
289 font_info *f = font_table[fontno];
290 tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
291 for (conditional_bold *p = cond_bold_list; p; p = p->next)
292 if (p->fontno == fontno) {
294 spec.bold_offset = p->offset;
297 if (!spec.is_bold && is_bold) {
299 spec.bold_offset = bold_offset;
301 spec.track_kern = track_kern.compute(fs.to_scaled_points());
302 spec.ligature_mode = global_ligature_mode;
303 spec.kern_mode = global_kern_mode;
304 switch (is_constant_spaced) {
305 case CONSTANT_SPACE_NONE:
307 case CONSTANT_SPACE_ABSOLUTE:
308 spec.is_constant_spaced = 1;
309 spec.constant_space_width = constant_space;
311 case CONSTANT_SPACE_RELATIVE:
312 spec.is_constant_spaced = 1;
313 spec.constant_space_width
314 = scale(constant_space*fs.to_scaled_points(),
321 if (fontno != number)
322 return make_tfont(spec);
323 // save font for comparison purposes
324 last_tfont = make_tfont(spec);
325 // save font related values not contained in tfont
327 last_height = height;
329 last_ligature_mode = global_ligature_mode;
330 last_kern_mode = global_kern_mode;
335 int font_info::get_bold(hunits *res)
345 void font_info::unbold()
353 void font_info::set_bold(hunits offset)
355 if (!is_bold || offset != bold_offset) {
357 bold_offset = offset;
362 void font_info::set_conditional_bold(int fontno, hunits offset)
364 for (conditional_bold *p = cond_bold_list; p; p = p->next)
365 if (p->fontno == fontno) {
366 if (offset != p->offset) {
372 cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
375 conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
376 : next(x), fontno(f), offset(h)
380 void font_info::conditional_unbold(int fontno)
382 for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
383 if ((*p)->fontno == fontno) {
384 conditional_bold *tem = *p;
392 void font_info::set_constant_space(constant_space_type type, units x)
394 if (type != is_constant_spaced
395 || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
397 is_constant_spaced = type;
402 void font_info::set_track_kern(track_kerning_function &tk)
404 if (track_kern != tk) {
410 void font_info::flush()
415 int font_info::is_named(symbol s)
417 return internal_name == s;
420 symbol font_info::get_name()
422 return internal_name;
425 symbol get_font_name(int fontno, environment *env)
427 symbol f = font_table[fontno]->get_name();
428 if (font_table[fontno]->is_style()) {
429 return concat(env->get_family()->nm, f);
434 symbol get_style_name(int fontno)
436 if (font_table[fontno]->is_style())
437 return font_table[fontno]->get_name();
442 hunits font_info::get_space_width(font_size fs, int space_sz)
444 if (is_constant_spaced == CONSTANT_SPACE_NONE)
445 return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
447 else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
448 return constant_space;
450 return scale(constant_space*fs.to_scaled_points(),
451 units_per_inch, 36*72*sizescale);
454 hunits font_info::get_narrow_space_width(font_size fs)
456 charinfo *ci = get_charinfo(symbol("|"));
457 if (fm->contains(ci->as_glyph()))
458 return hunits(fm->get_width(ci->as_glyph(), fs.to_scaled_points()));
460 return hunits(fs.to_units()/6);
463 hunits font_info::get_half_narrow_space_width(font_size fs)
465 charinfo *ci = get_charinfo(symbol("^"));
466 if (fm->contains(ci->as_glyph()))
467 return hunits(fm->get_width(ci->as_glyph(), fs.to_scaled_points()));
469 return hunits(fs.to_units()/12);
474 tfont_spec::tfont_spec(symbol nm, int n, font *f,
475 font_size s, int h, int sl)
476 : name(nm), input_position(n), fm(f), size(s),
477 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
480 if (height == size.to_scaled_points())
484 int tfont_spec::operator==(const tfont_spec &spec)
488 && input_position == spec.input_position
490 && height == spec.height
491 && slant == spec.slant
493 ? (spec.is_bold && bold_offset == spec.bold_offset)
495 && track_kern == spec.track_kern
496 && (is_constant_spaced
497 ? (spec.is_constant_spaced
498 && constant_space_width == spec.constant_space_width)
499 : !spec.is_constant_spaced)
500 && ligature_mode == spec.ligature_mode
501 && kern_mode == spec.kern_mode)
507 tfont_spec tfont_spec::plain()
509 return tfont_spec(name, input_position, fm, size, height, slant);
512 hunits tfont::get_width(charinfo *c)
514 if (is_constant_spaced)
515 return constant_space_width;
517 return (hunits(fm->get_width(c->as_glyph(), size.to_scaled_points()))
518 + track_kern + bold_offset);
520 return (hunits(fm->get_width(c->as_glyph(), size.to_scaled_points()))
524 vunits tfont::get_char_height(charinfo *c)
526 vunits v = fm->get_height(c->as_glyph(), size.to_scaled_points());
527 if (height != 0 && height != size.to_scaled_points())
528 return scale(v, height, size.to_scaled_points());
533 vunits tfont::get_char_depth(charinfo *c)
535 vunits v = fm->get_depth(c->as_glyph(), size.to_scaled_points());
536 if (height != 0 && height != size.to_scaled_points())
537 return scale(v, height, size.to_scaled_points());
542 hunits tfont::get_char_skew(charinfo *c)
544 return hunits(fm->get_skew(c->as_glyph(), size.to_scaled_points(), slant));
547 hunits tfont::get_italic_correction(charinfo *c)
549 return hunits(fm->get_italic_correction(c->as_glyph(), size.to_scaled_points()));
552 hunits tfont::get_left_italic_correction(charinfo *c)
554 return hunits(fm->get_left_italic_correction(c->as_glyph(),
555 size.to_scaled_points()));
558 hunits tfont::get_subscript_correction(charinfo *c)
560 return hunits(fm->get_subscript_correction(c->as_glyph(),
561 size.to_scaled_points()));
564 inline int tfont::get_input_position()
566 return input_position;
569 inline int tfont::contains(charinfo *ci)
571 return fm->contains(ci->as_glyph());
574 inline int tfont::get_character_type(charinfo *ci)
576 return fm->get_character_type(ci->as_glyph());
579 inline int tfont::get_bold(hunits *res)
589 inline int tfont::get_constant_space(hunits *res)
591 if (is_constant_spaced) {
592 *res = constant_space_width;
599 inline hunits tfont::get_track_kern()
604 inline tfont *tfont::get_plain()
606 return plain_version;
609 inline font_size tfont::get_size()
614 inline int tfont::get_zoom()
616 return fm->get_zoom();
619 inline symbol tfont::get_name()
624 inline int tfont::get_height()
629 inline int tfont::get_slant()
634 symbol SYMBOL_ff("ff");
635 symbol SYMBOL_fi("fi");
636 symbol SYMBOL_fl("fl");
637 symbol SYMBOL_Fi("Fi");
638 symbol SYMBOL_Fl("Fl");
640 charinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
642 if (ligature_mode == 0)
645 if (c1->get_ascii_code() == 'f') {
646 switch (c2->get_ascii_code()) {
648 if (fm->has_ligature(font::LIG_ff))
649 ci = get_charinfo(SYMBOL_ff);
652 if (fm->has_ligature(font::LIG_fi))
653 ci = get_charinfo(SYMBOL_fi);
656 if (fm->has_ligature(font::LIG_fl))
657 ci = get_charinfo(SYMBOL_fl);
661 else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
662 switch (c2->get_ascii_code()) {
664 if (fm->has_ligature(font::LIG_ffi))
665 ci = get_charinfo(SYMBOL_Fi);
668 if (fm->has_ligature(font::LIG_ffl))
669 ci = get_charinfo(SYMBOL_Fl);
673 if (ci != 0 && fm->contains(ci->as_glyph()))
678 inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
683 int n = fm->get_kern(c1->as_glyph(),
685 size.to_scaled_points());
695 tfont *tfont::tfont_list = 0;
697 tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
701 tfont_spec plain_spec = plain();
703 for (p = tfont_list; p; p = p->next)
704 if (*p == plain_spec) {
709 plain_version = new tfont(plain_spec);
714 class real_output_file : public output_file {
715 #ifndef POPEN_MISSING
718 int printing; // decision via optional page list
719 int output_on; // \O[0] or \O[1] escape calls
720 virtual void really_transparent_char(unsigned char) = 0;
721 virtual void really_print_line(hunits x, vunits y, node *n,
722 vunits before, vunits after, hunits width) = 0;
723 virtual void really_begin_page(int pageno, vunits page_length) = 0;
724 virtual void really_copy_file(hunits x, vunits y, const char *filename);
725 virtual void really_put_filename(const char *, int);
726 virtual void really_on();
727 virtual void really_off();
733 void transparent_char(unsigned char);
734 void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
735 void begin_page(int pageno, vunits page_length);
736 void put_filename(const char *, int);
741 void copy_file(hunits x, vunits y, const char *filename);
744 class suppress_output_file : public real_output_file {
746 suppress_output_file();
747 void really_transparent_char(unsigned char);
748 void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
749 void really_begin_page(int pageno, vunits page_length);
752 class ascii_output_file : public real_output_file {
755 void really_transparent_char(unsigned char);
756 void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
757 void really_begin_page(int pageno, vunits page_length);
758 void outc(unsigned char c);
759 void outs(const char *s);
762 void ascii_output_file::outc(unsigned char c)
767 void ascii_output_file::outs(const char *s)
777 class troff_output_file : public real_output_file {
786 tfont *current_tfont;
787 color *current_fill_color;
788 color *current_glyph_color;
789 int current_font_number;
790 symbol *font_position;
792 enum { TBUF_SIZE = 256 };
793 char tbuf[TBUF_SIZE];
801 void put(unsigned char c);
803 void put(unsigned int i);
804 void put(const char *s);
805 void set_font(tfont *tf);
809 ~troff_output_file();
810 void trailer(vunits page_length);
811 void put_char(charinfo *, tfont *, color *, color *);
812 void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits);
815 void moveto(hunits, vunits);
816 void start_special(tfont *, color *, color *, int = 0);
817 void start_special();
818 void special_char(unsigned char c);
821 void really_transparent_char(unsigned char c);
822 void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
823 void really_begin_page(int pageno, vunits page_length);
824 void really_copy_file(hunits x, vunits y, const char *filename);
825 void really_put_filename(const char *, int);
828 void draw(char, hvpair *, int, font_size, color *, color *);
829 void determine_line_limits (char code, hvpair *point, int npoints);
830 void check_charinfo(tfont *tf, charinfo *ci);
831 void glyph_color(color *c);
832 void fill_color(color *c);
833 int get_hpos() { return hpos; }
834 int get_vpos() { return vpos; }
835 void add_to_tag_list(string s);
836 friend void space_char_hmotion_node::tprint(troff_output_file *);
837 friend void unbreakable_space_node::tprint(troff_output_file *);
840 static void put_string(const char *s, FILE *fp)
842 for (; *s != '\0'; ++s)
846 inline void troff_output_file::put(char c)
851 inline void troff_output_file::put(unsigned char c)
856 inline void troff_output_file::put(const char *s)
861 inline void troff_output_file::put(int i)
863 put_string(i_to_a(i), fp);
866 inline void troff_output_file::put(unsigned int i)
868 put_string(ui_to_a(i), fp);
871 void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol,
883 void troff_output_file::start_special()
890 void troff_output_file::special_char(unsigned char c)
897 void troff_output_file::end_special()
902 inline void troff_output_file::moveto(hunits h, vunits v)
908 void troff_output_file::really_print_line(hunits x, vunits y, node *n,
909 vunits before, vunits after, hunits)
913 // Check whether we should push the current troff state and use
914 // the state at the start of the invocation of this diversion.
915 if (n->div_nest_level > cur_div_level && n->push_state) {
916 state.push_state(n->push_state);
917 cur_div_level = n->div_nest_level;
919 // Has the current diversion level decreased? Then we must pop the
921 while (n->div_nest_level < cur_div_level) {
923 cur_div_level = n->div_nest_level;
925 // Now check whether the state has changed.
926 if ((is_on() || n->force_tprint())
927 && (state.changed(n->state) || n->is_tag() || n->is_special)) {
932 state.flush(fp, n->state, tag_list);
933 tag_list = string("");
940 // This ensures that transparent throughput will have a more predictable
946 put(before.to_units());
948 put(after.to_units());
952 inline void troff_output_file::word_marker()
959 inline void troff_output_file::right(hunits n)
961 hpos += n.to_units();
964 inline void troff_output_file::down(vunits n)
966 vpos += n.to_units();
969 void troff_output_file::do_motion()
980 if (hpos != output_hpos) {
981 units n = hpos - output_hpos;
982 if (n > 0 && n < hpos) {
992 if (vpos != output_vpos) {
993 units n = vpos - output_vpos;
994 if (n > 0 && n < vpos) {
1010 void troff_output_file::flush_tbuf()
1026 check_output_limits(hpos, vpos);
1027 check_output_limits(hpos, vpos - current_size);
1029 for (int i = 0; i < tbuf_len; i++)
1035 void troff_output_file::check_charinfo(tfont *tf, charinfo *ci)
1040 int height = tf->get_char_height(ci).to_units();
1041 int width = tf->get_width(ci).to_units()
1042 + tf->get_italic_correction(ci).to_units();
1043 int depth = tf->get_char_depth(ci).to_units();
1044 check_output_limits(output_hpos, output_vpos - height);
1045 check_output_limits(output_hpos + width, output_vpos + depth);
1048 void troff_output_file::put_char_width(charinfo *ci, tfont *tf,
1049 color *gcol, color *fcol,
1052 int kk = k.to_units();
1055 hpos += w.to_units() + kk;
1059 unsigned char c = ci->get_ascii_code();
1065 check_charinfo(tf, ci);
1066 if (ci->numbered()) {
1068 put(ci->get_number());
1072 const char *s = ci->nm.contents();
1081 hpos += w.to_units() + kk;
1083 else if (tcommand_flag) {
1084 if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
1085 && (!gcol || gcol == current_glyph_color)
1086 && (!fcol || fcol == current_fill_color)
1088 && tbuf_len < TBUF_SIZE) {
1089 check_charinfo(tf, ci);
1090 tbuf[tbuf_len++] = c;
1091 output_hpos += w.to_units() + kk;
1099 check_charinfo(tf, ci);
1100 tbuf[tbuf_len++] = c;
1101 output_hpos += w.to_units() + kk;
1107 int n = hpos - output_hpos;
1108 check_charinfo(tf, ci);
1109 // check_output_limits(output_hpos, output_vpos);
1110 if (vpos == output_vpos
1111 && (!gcol || gcol == current_glyph_color)
1112 && (!fcol || fcol == current_fill_color)
1113 && n > 0 && n < 100 && !force_motion) {
1114 put(char(n/10 + '0'));
1115 put(char(n%10 + '0'));
1126 hpos += w.to_units() + kk;
1130 void troff_output_file::put_char(charinfo *ci, tfont *tf,
1131 color *gcol, color *fcol)
1137 unsigned char c = ci->get_ascii_code();
1143 if (ci->numbered()) {
1145 put(ci->get_number());
1149 const char *s = ci->nm.contents();
1160 int n = hpos - output_hpos;
1161 if (vpos == output_vpos
1162 && (!gcol || gcol == current_glyph_color)
1163 && (!fcol || fcol == current_fill_color)
1164 && n > 0 && n < 100) {
1165 put(char(n/10 + '0'));
1166 put(char(n%10 + '0'));
1181 // set_font calls `flush_tbuf' if necessary.
1183 void troff_output_file::set_font(tfont *tf)
1185 if (current_tfont == tf)
1188 int n = tf->get_input_position();
1189 symbol nm = tf->get_name();
1190 if (n >= nfont_positions || font_position[n] != nm) {
1196 if (n >= nfont_positions) {
1197 int old_nfont_positions = nfont_positions;
1198 symbol *old_font_position = font_position;
1199 nfont_positions *= 3;
1200 nfont_positions /= 2;
1201 if (nfont_positions <= n)
1202 nfont_positions = n + 10;
1203 font_position = new symbol[nfont_positions];
1204 memcpy(font_position, old_font_position,
1205 old_nfont_positions*sizeof(symbol));
1206 a_delete old_font_position;
1208 font_position[n] = nm;
1210 if (current_font_number != n) {
1214 current_font_number = n;
1216 int zoom = tf->get_zoom();
1219 size = scale(tf->get_size().to_scaled_points(),
1222 size = tf->get_size().to_scaled_points();
1223 if (current_size != size) {
1227 current_size = size;
1229 int slant = tf->get_slant();
1230 if (current_slant != slant) {
1234 current_slant = slant;
1236 int height = tf->get_height();
1237 if (current_height != height) {
1239 put(height == 0 ? current_size : height);
1241 current_height = height;
1246 // fill_color calls `flush_tbuf' and `do_motion' if necessary.
1248 void troff_output_file::fill_color(color *col)
1250 if (!col || current_fill_color == col)
1252 current_fill_color = col;
1258 unsigned int components[4];
1260 cs = col->get_components(components);
1299 // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1301 void troff_output_file::glyph_color(color *col)
1303 if (!col || current_glyph_color == col)
1305 current_glyph_color = col;
1309 // grotty doesn't like a color command if the vertical position is zero.
1312 unsigned int components[4];
1314 cs = col->get_components(components);
1353 void troff_output_file::add_to_tag_list(string s)
1355 if (tag_list == string(""))
1358 tag_list += string("\n");
1363 // determine_line_limits - works out the smallest box which will contain
1364 // the entity, code, built from the point array.
1365 void troff_output_file::determine_line_limits(char code, hvpair *point,
1376 // only the h field is used when defining a circle
1377 check_output_limits(output_hpos,
1378 output_vpos - point[0].h.to_units()/2);
1379 check_output_limits(output_hpos + point[0].h.to_units(),
1380 output_vpos + point[0].h.to_units()/2);
1384 check_output_limits(output_hpos,
1385 output_vpos - point[0].v.to_units()/2);
1386 check_output_limits(output_hpos + point[0].h.to_units(),
1387 output_vpos + point[0].v.to_units()/2);
1393 check_output_limits(x, y);
1394 for (i = 0; i < npoints; i++) {
1395 x += point[i].h.to_units();
1396 y += point[i].v.to_units();
1397 check_output_limits(x, y);
1403 for (i = 0; i < npoints; i++) {
1404 x += point[i].h.to_units();
1405 y += point[i].v.to_units();
1406 check_output_limits(x, y);
1412 int minx, miny, maxx, maxy;
1415 p[0] = point[0].h.to_units();
1416 p[1] = point[0].v.to_units();
1417 p[2] = point[1].h.to_units();
1418 p[3] = point[1].v.to_units();
1419 if (adjust_arc_center(p, c)) {
1420 check_output_arc_limits(x, y,
1421 p[0], p[1], p[2], p[3],
1423 &minx, &maxx, &miny, &maxy);
1424 check_output_limits(minx, miny);
1425 check_output_limits(maxx, maxy);
1432 check_output_limits(x, y);
1433 for (i = 0; i < npoints; i++) {
1434 x += point[i].h.to_units();
1435 y += point[i].v.to_units();
1436 check_output_limits(x, y);
1442 for (i = 0; i < npoints; i++) {
1443 x += point[i].h.to_units();
1444 y += point[i].v.to_units();
1445 check_output_limits(x, y);
1450 void troff_output_file::draw(char code, hvpair *point, int npoints,
1451 font_size fsize, color *gcol, color *fcol)
1459 int size = fsize.to_scaled_points();
1460 if (current_size != size) {
1464 current_size = size;
1471 put(point[0].h.to_units());
1474 for (i = 0; i < npoints; i++) {
1476 put(point[i].h.to_units());
1478 put(point[i].v.to_units());
1480 determine_line_limits(code, point, npoints);
1483 for (i = 0; i < npoints; i++)
1484 output_hpos += point[i].h.to_units();
1487 for (i = 0; i < npoints; i++)
1488 output_vpos += point[i].v.to_units();
1495 void troff_output_file::really_on()
1502 void troff_output_file::really_off()
1507 void troff_output_file::really_put_filename(const char *filename, int po)
1519 void troff_output_file::really_begin_page(int pageno, vunits page_length)
1523 if (page_length > V0) {
1525 put(page_length.to_units());
1532 current_font_number = -1;
1534 // current_height = 0;
1535 // current_slant = 0;
1541 for (int i = 0; i < nfont_positions; i++)
1542 font_position[i] = NULL_SYMBOL;
1548 void troff_output_file::really_copy_file(hunits x, vunits y,
1549 const char *filename)
1555 FILE *ifp = include_search_path.open_file_cautious(filename);
1557 error("can't open `%1': %2", filename, strerror(errno));
1560 while ((c = getc(ifp)) != EOF)
1567 current_font_number = -1;
1568 for (int i = 0; i < nfont_positions; i++)
1569 font_position[i] = NULL_SYMBOL;
1572 void troff_output_file::really_transparent_char(unsigned char c)
1577 troff_output_file::~troff_output_file()
1579 a_delete font_position;
1582 void troff_output_file::trailer(vunits page_length)
1585 if (page_length > V0) {
1588 put(page_length.to_units());
1594 troff_output_file::troff_output_file()
1595 : current_slant(0), current_height(0), current_fill_color(0),
1596 current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0),
1599 font_position = new symbol[nfont_positions];
1604 put(units_per_inch);
1615 output_file *the_output = 0;
1617 output_file::output_file()
1621 output_file::~output_file()
1625 void output_file::trailer(vunits)
1629 void output_file::put_filename(const char *, int)
1633 void output_file::on()
1637 void output_file::off()
1641 real_output_file::real_output_file()
1642 : printing(0), output_on(1)
1644 #ifndef POPEN_MISSING
1646 if ((fp = popen(pipe_command, POPEN_WT)) != 0) {
1650 error("pipe open failed: %1", strerror(errno));
1653 #endif /* not POPEN_MISSING */
1657 real_output_file::~real_output_file()
1661 // To avoid looping, set fp to 0 before calling fatal().
1662 if (ferror(fp) || fflush(fp) < 0) {
1664 fatal("error writing output file");
1666 #ifndef POPEN_MISSING
1668 int result = pclose(fp);
1671 fatal("pclose failed");
1672 if (!WIFEXITED(result))
1673 error("output process `%1' got fatal signal %2",
1675 WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result));
1677 int exit_status = WEXITSTATUS(result);
1678 if (exit_status != 0)
1679 error("output process `%1' exited with status %2",
1680 pipe_command, exit_status);
1684 #endif /* not POPEN MISSING */
1685 if (fclose(fp) < 0) {
1687 fatal("error closing output file");
1691 void real_output_file::flush()
1694 fatal("error writing output file");
1697 int real_output_file::is_printing()
1702 void real_output_file::begin_page(int pageno, vunits page_length)
1704 printing = in_output_page_list(pageno);
1706 really_begin_page(pageno, page_length);
1709 void real_output_file::copy_file(hunits x, vunits y, const char *filename)
1711 if (printing && output_on)
1712 really_copy_file(x, y, filename);
1713 check_output_limits(x.to_units(), y.to_units());
1716 void real_output_file::transparent_char(unsigned char c)
1718 if (printing && output_on)
1719 really_transparent_char(c);
1722 void real_output_file::print_line(hunits x, vunits y, node *n,
1723 vunits before, vunits after, hunits width)
1726 really_print_line(x, y, n, before, after, width);
1727 delete_node_list(n);
1730 void real_output_file::really_copy_file(hunits, vunits, const char *)
1735 void real_output_file::put_filename(const char *filename, int po)
1737 really_put_filename(filename, po);
1740 void real_output_file::really_put_filename(const char *, int)
1744 void real_output_file::on()
1751 void real_output_file::off()
1757 int real_output_file::is_on()
1762 void real_output_file::really_on()
1766 void real_output_file::really_off()
1770 /* ascii_output_file */
1772 void ascii_output_file::really_transparent_char(unsigned char c)
1777 void ascii_output_file::really_print_line(hunits, vunits, node *n,
1778 vunits, vunits, hunits)
1781 n->ascii_print(this);
1787 void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
1789 fputs("<beginning of page>\n", fp);
1792 ascii_output_file::ascii_output_file()
1796 /* suppress_output_file */
1798 suppress_output_file::suppress_output_file()
1802 void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits)
1806 void suppress_output_file::really_begin_page(int, vunits)
1810 void suppress_output_file::really_transparent_char(unsigned char)
1814 /* glyphs, ligatures, kerns, discretionary breaks */
1816 class charinfo_node : public node {
1820 charinfo_node(charinfo *, statem *, int, node * = 0);
1821 int ends_sentence();
1822 int overlaps_vertically();
1823 int overlaps_horizontally();
1826 charinfo_node::charinfo_node(charinfo *c, statem *s, int pop, node *x)
1827 : node(x, s, pop), ci(c)
1831 int charinfo_node::ends_sentence()
1833 if (ci->ends_sentence())
1835 else if (ci->transparent())
1841 int charinfo_node::overlaps_horizontally()
1843 return ci->overlaps_horizontally();
1846 int charinfo_node::overlaps_vertically()
1848 return ci->overlaps_vertically();
1851 class glyph_node : public charinfo_node {
1852 static glyph_node *free_list;
1856 color *fcol; /* this is needed for grotty */
1859 glyph_node(charinfo *, tfont *, color *, color *, hunits,
1860 statem *, int, node * = 0);
1863 void *operator new(size_t);
1864 void operator delete(void *);
1865 glyph_node(charinfo *, tfont *, color *, color *,
1866 statem *, int, node * = 0);
1869 node *merge_glyph_node(glyph_node *);
1870 node *merge_self(node *);
1872 node *last_char_node();
1874 void vertical_extent(vunits *, vunits *);
1875 hunits subscript_correction();
1876 hunits italic_correction();
1877 hunits left_italic_correction();
1879 hyphenation_type get_hyphenation_type();
1881 color *get_glyph_color();
1882 color *get_fill_color();
1883 void tprint(troff_output_file *);
1884 void zero_width_tprint(troff_output_file *);
1885 hyphen_list *get_hyphen_list(hyphen_list *, int *);
1886 node *add_self(node *, hyphen_list **);
1887 void ascii_print(ascii_output_file *);
1888 void asciify(macro *);
1889 int character_type();
1897 glyph_node *glyph_node::free_list = 0;
1899 class ligature_node : public glyph_node {
1903 ligature_node(charinfo *, tfont *, color *, color *, hunits,
1904 node *, node *, statem *, int, node * = 0);
1907 void *operator new(size_t);
1908 void operator delete(void *);
1909 ligature_node(charinfo *, tfont *, color *, color *,
1910 node *, node *, statem *, int, node * = 0);
1913 node *add_self(node *, hyphen_list **);
1914 hyphen_list *get_hyphen_list(hyphen_list *, int *);
1915 void ascii_print(ascii_output_file *);
1916 void asciify(macro *);
1923 class kern_pair_node : public node {
1928 kern_pair_node(hunits, node *, node *, statem *, int, node * = 0);
1931 node *merge_glyph_node(glyph_node *);
1932 node *add_self(node *, hyphen_list **);
1933 hyphen_list *get_hyphen_list(hyphen_list *, int *);
1934 node *add_discretionary_hyphen();
1936 node *last_char_node();
1937 hunits italic_correction();
1938 hunits subscript_correction();
1939 void tprint(troff_output_file *);
1940 hyphenation_type get_hyphenation_type();
1941 int ends_sentence();
1942 void ascii_print(ascii_output_file *);
1943 void asciify(macro *);
1948 void vertical_extent(vunits *, vunits *);
1951 class dbreak_node : public node {
1956 dbreak_node(node *, node *, statem *, int, node * = 0);
1959 node *merge_glyph_node(glyph_node *);
1960 node *add_discretionary_hyphen();
1962 node *last_char_node();
1963 hunits italic_correction();
1964 hunits subscript_correction();
1965 void tprint(troff_output_file *);
1966 breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
1969 int ends_sentence();
1970 void split(int, node **, node **);
1971 hyphenation_type get_hyphenation_type();
1972 void ascii_print(ascii_output_file *);
1973 void asciify(macro *);
1980 void *glyph_node::operator new(size_t n)
1982 assert(n == sizeof(glyph_node));
1984 const int BLOCK = 1024;
1985 free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
1986 for (int i = 0; i < BLOCK - 1; i++)
1987 free_list[i].next = free_list + i + 1;
1988 free_list[BLOCK-1].next = 0;
1990 glyph_node *p = free_list;
1991 free_list = (glyph_node *)(free_list->next);
1996 void *ligature_node::operator new(size_t n)
2001 void glyph_node::operator delete(void *p)
2004 ((glyph_node *)p)->next = free_list;
2005 free_list = (glyph_node *)p;
2009 void ligature_node::operator delete(void *p)
2014 glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc,
2015 statem *s, int pop, node *x)
2016 : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc)
2019 wid = tf->get_width(ci);
2024 glyph_node::glyph_node(charinfo *c, tfont *t,
2025 color *gc, color *fc, hunits w,
2026 statem *s, int pop, node *x)
2027 : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc), wid(w)
2032 node *glyph_node::copy()
2035 return new glyph_node(ci, tf, gcol, fcol, wid, state, div_nest_level);
2037 return new glyph_node(ci, tf, gcol, fcol, state, div_nest_level);
2041 node *glyph_node::merge_self(node *nd)
2043 return nd->merge_glyph_node(this);
2046 int glyph_node::character_type()
2048 return tf->get_character_type(ci);
2051 node *glyph_node::add_self(node *n, hyphen_list **p)
2053 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
2056 if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
2061 nn = nn->add_discretionary_hyphen();
2062 hyphen_list *pp = *p;
2068 units glyph_node::size()
2070 return tf->get_size().to_units();
2073 hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail, int *count)
2076 return new hyphen_list(ci->get_hyphenation_code(), tail);
2079 tfont *node::get_tfont()
2084 tfont *glyph_node::get_tfont()
2089 color *node::get_glyph_color()
2094 color *glyph_node::get_glyph_color()
2099 color *node::get_fill_color()
2104 color *glyph_node::get_fill_color()
2109 node *node::merge_glyph_node(glyph_node *)
2114 node *glyph_node::merge_glyph_node(glyph_node *gn)
2116 if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) {
2118 if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
2121 return new ligature_node(lig, tf, gcol, fcol, this, gn, state,
2122 gn->div_nest_level, next1);
2125 if (tf->get_kern(ci, gn->ci, &kern)) {
2128 return new kern_pair_node(kern, this, gn, state,
2129 gn->div_nest_level, next1);
2138 hunits glyph_node::width()
2143 return tf->get_width(ci);
2147 node *glyph_node::last_char_node()
2152 void glyph_node::vertical_extent(vunits *min, vunits *max)
2154 *min = -tf->get_char_height(ci);
2155 *max = tf->get_char_depth(ci);
2158 hunits glyph_node::skew()
2160 return tf->get_char_skew(ci);
2163 hunits glyph_node::subscript_correction()
2165 return tf->get_subscript_correction(ci);
2168 hunits glyph_node::italic_correction()
2170 return tf->get_italic_correction(ci);
2173 hunits glyph_node::left_italic_correction()
2175 return tf->get_left_italic_correction(ci);
2178 hyphenation_type glyph_node::get_hyphenation_type()
2180 return HYPHEN_MIDDLE;
2183 void glyph_node::ascii_print(ascii_output_file *ascii)
2185 unsigned char c = ci->get_ascii_code();
2189 ascii->outs(ci->nm.contents());
2192 void glyph_node::debug_node()
2194 unsigned char c = ci->get_ascii_code();
2195 fprintf(stderr, "{ %s [", type());
2197 fprintf(stderr, "%c", c);
2199 fprintf(stderr, ci->nm.contents());
2201 fprintf(stderr, " <push_state>");
2203 state->display_state();
2204 fprintf(stderr, " nest level %d", div_nest_level);
2205 fprintf(stderr, "]}\n");
2209 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2210 node *gn1, node *gn2, statem *s,
2212 : glyph_node(c, t, gc, fc, s, pop, x), n1(gn1), n2(gn2)
2217 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2218 hunits w, node *gn1, node *gn2, statem *s,
2220 : glyph_node(c, t, gc, fc, w, s, pop, x), n1(gn1), n2(gn2)
2225 ligature_node::~ligature_node()
2231 node *ligature_node::copy()
2234 return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy(),
2235 state, div_nest_level);
2237 return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy(),
2238 state, div_nest_level);
2242 void ligature_node::ascii_print(ascii_output_file *ascii)
2244 n1->ascii_print(ascii);
2245 n2->ascii_print(ascii);
2248 hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail, int *count)
2250 hyphen_list *hl = n2->get_hyphen_list(tail, count);
2251 return n1->get_hyphen_list(hl, count);
2254 node *ligature_node::add_self(node *n, hyphen_list **p)
2256 n = n1->add_self(n, p);
2257 n = n2->add_self(n, p);
2263 kern_pair_node::kern_pair_node(hunits n, node *first, node *second,
2264 statem* s, int pop, node *x)
2265 : node(x, s, pop), amount(n), n1(first), n2(second)
2269 dbreak_node::dbreak_node(node *n, node *p, statem *s, int pop, node *x)
2270 : node(x, s, pop), none(n), pre(p), post(0)
2274 node *dbreak_node::merge_glyph_node(glyph_node *gn)
2276 glyph_node *gn2 = (glyph_node *)gn->copy();
2277 node *new_none = none ? none->merge_glyph_node(gn) : 0;
2278 node *new_post = post ? post->merge_glyph_node(gn2) : 0;
2279 if (new_none == 0 && new_post == 0) {
2298 node *kern_pair_node::merge_glyph_node(glyph_node *gn)
2300 node *nd = n2->merge_glyph_node(gn);
2304 nd = n2->merge_self(n1);
2315 hunits kern_pair_node::italic_correction()
2317 return n2->italic_correction();
2320 hunits kern_pair_node::subscript_correction()
2322 return n2->subscript_correction();
2325 void kern_pair_node::vertical_extent(vunits *min, vunits *max)
2327 n1->vertical_extent(min, max);
2329 n2->vertical_extent(&min2, &max2);
2336 node *kern_pair_node::add_discretionary_hyphen()
2338 tfont *tf = n2->get_tfont();
2340 if (tf->contains(soft_hyphen_char)) {
2341 color *gcol = n2->get_glyph_color();
2342 color *fcol = n2->get_fill_color();
2346 glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol,
2347 state, div_nest_level);
2348 node *nn = n->merge_glyph_node(gn);
2353 return new dbreak_node(this, nn, state, div_nest_level, next1);
2359 kern_pair_node::~kern_pair_node()
2367 dbreak_node::~dbreak_node()
2369 delete_node_list(pre);
2370 delete_node_list(post);
2371 delete_node_list(none);
2374 node *kern_pair_node::copy()
2376 return new kern_pair_node(amount, n1->copy(), n2->copy(), state,
2380 node *copy_node_list(node *n)
2384 node *nn = n->copy();
2398 void delete_node_list(node *n)
2407 node *dbreak_node::copy()
2409 dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre),
2410 state, div_nest_level);
2411 p->post = copy_node_list(post);
2415 hyphen_list *node::get_hyphen_list(hyphen_list *tail, int *)
2420 hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail, int *count)
2422 hyphen_list *hl = n2->get_hyphen_list(tail, count);
2423 return n1->get_hyphen_list(hl, count);
2426 class hyphen_inhibitor_node : public node {
2428 hyphen_inhibitor_node(node * = 0);
2434 hyphenation_type get_hyphenation_type();
2437 hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd)
2441 node *hyphen_inhibitor_node::copy()
2443 return new hyphen_inhibitor_node;
2446 int hyphen_inhibitor_node::same(node *)
2451 const char *hyphen_inhibitor_node::type()
2453 return "hyphen_inhibitor_node";
2456 int hyphen_inhibitor_node::force_tprint()
2461 int hyphen_inhibitor_node::is_tag()
2466 hyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
2468 return HYPHEN_INHIBIT;
2471 /* add_discretionary_hyphen methods */
2473 node *dbreak_node::add_discretionary_hyphen()
2476 post = post->add_discretionary_hyphen();
2478 none = none->add_discretionary_hyphen();
2482 node *node::add_discretionary_hyphen()
2484 tfont *tf = get_tfont();
2486 return new hyphen_inhibitor_node(this);
2487 if (tf->contains(soft_hyphen_char)) {
2488 color *gcol = get_glyph_color();
2489 color *fcol = get_fill_color();
2493 glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol,
2494 state, div_nest_level);
2495 node *n1 = n->merge_glyph_node(gn);
2500 return new dbreak_node(this, n1, state, div_nest_level, next1);
2505 node *node::merge_self(node *)
2510 node *node::add_self(node *n, hyphen_list ** /*p*/)
2516 node *kern_pair_node::add_self(node *n, hyphen_list **p)
2518 n = n1->add_self(n, p);
2519 n = n2->add_self(n, p);
2525 hunits node::width()
2530 node *node::last_char_node()
2535 int node::force_tprint()
2545 hunits hmotion_node::width()
2552 return points_to_units(10);
2555 void node::debug_node()
2557 fprintf(stderr, "{ %s ", type());
2559 fprintf(stderr, " <push_state>");
2561 fprintf(stderr, " <state>");
2562 fprintf(stderr, " nest level %d", div_nest_level);
2563 fprintf(stderr, " }\n");
2567 void node::debug_node_list()
2578 hunits kern_pair_node::width()
2580 return n1->width() + n2->width() + amount;
2583 node *kern_pair_node::last_char_node()
2585 node *nd = n2->last_char_node();
2588 return n1->last_char_node();
2591 hunits dbreak_node::width()
2594 for (node *n = none; n != 0; n = n->next)
2599 node *dbreak_node::last_char_node()
2601 for (node *n = none; n; n = n->next) {
2602 node *last_node = n->last_char_node();
2609 hunits dbreak_node::italic_correction()
2611 return none ? none->italic_correction() : H0;
2614 hunits dbreak_node::subscript_correction()
2616 return none ? none->subscript_correction() : H0;
2619 class italic_corrected_node : public node {
2623 italic_corrected_node(node *, hunits, statem *, int, node * = 0);
2624 ~italic_corrected_node();
2626 void ascii_print(ascii_output_file *);
2627 void asciify(macro *);
2629 node *last_char_node();
2630 void vertical_extent(vunits *, vunits *);
2631 int ends_sentence();
2632 int overlaps_horizontally();
2633 int overlaps_vertically();
2635 hyphenation_type get_hyphenation_type();
2637 hyphen_list *get_hyphen_list(hyphen_list *, int *);
2638 int character_type();
2639 void tprint(troff_output_file *);
2640 hunits subscript_correction();
2642 node *add_self(node *, hyphen_list **);
2648 node *node::add_italic_correction(hunits *wd)
2650 hunits ic = italic_correction();
2657 return new italic_corrected_node(this, ic, state, div_nest_level, next1);
2661 italic_corrected_node::italic_corrected_node(node *nn, hunits xx, statem *s,
2663 : node(p, s, pop), n(nn), x(xx)
2668 italic_corrected_node::~italic_corrected_node()
2673 node *italic_corrected_node::copy()
2675 return new italic_corrected_node(n->copy(), x, state, div_nest_level);
2678 hunits italic_corrected_node::width()
2680 return n->width() + x;
2683 void italic_corrected_node::vertical_extent(vunits *min, vunits *max)
2685 n->vertical_extent(min, max);
2688 void italic_corrected_node::tprint(troff_output_file *out)
2694 hunits italic_corrected_node::skew()
2696 return n->skew() - x/2;
2699 hunits italic_corrected_node::subscript_correction()
2701 return n->subscript_correction() - x;
2704 void italic_corrected_node::ascii_print(ascii_output_file *out)
2706 n->ascii_print(out);
2709 int italic_corrected_node::ends_sentence()
2711 return n->ends_sentence();
2714 int italic_corrected_node::overlaps_horizontally()
2716 return n->overlaps_horizontally();
2719 int italic_corrected_node::overlaps_vertically()
2721 return n->overlaps_vertically();
2724 node *italic_corrected_node::last_char_node()
2726 return n->last_char_node();
2729 tfont *italic_corrected_node::get_tfont()
2731 return n->get_tfont();
2734 hyphenation_type italic_corrected_node::get_hyphenation_type()
2736 return n->get_hyphenation_type();
2739 node *italic_corrected_node::add_self(node *nd, hyphen_list **p)
2741 nd = n->add_self(nd, p);
2742 hunits not_interested;
2743 nd = nd->add_italic_correction(¬_interested);
2749 hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail,
2752 return n->get_hyphen_list(tail, count);
2755 int italic_corrected_node::character_type()
2757 return n->character_type();
2760 class break_char_node : public node {
2765 break_char_node(node *, int, color *, node * = 0);
2766 break_char_node(node *, int, color *, statem *, int, node * = 0);
2770 vunits vertical_width();
2771 node *last_char_node();
2772 int character_type();
2773 int ends_sentence();
2774 node *add_self(node *, hyphen_list **);
2775 hyphen_list *get_hyphen_list(hyphen_list *, int *);
2776 void tprint(troff_output_file *);
2777 void zero_width_tprint(troff_output_file *);
2778 void ascii_print(ascii_output_file *);
2779 void asciify(macro *);
2780 hyphenation_type get_hyphenation_type();
2781 int overlaps_vertically();
2782 int overlaps_horizontally();
2791 break_char_node::break_char_node(node *n, int bc, color *c, node *x)
2792 : node(x), ch(n), break_code(bc), col(c)
2796 break_char_node::break_char_node(node *n, int bc, color *c, statem *s,
2798 : node(x, s, pop), ch(n), break_code(bc), col(c)
2802 break_char_node::~break_char_node()
2807 node *break_char_node::copy()
2809 return new break_char_node(ch->copy(), break_code, col, state,
2813 hunits break_char_node::width()
2818 vunits break_char_node::vertical_width()
2820 return ch->vertical_width();
2823 node *break_char_node::last_char_node()
2825 return ch->last_char_node();
2828 int break_char_node::character_type()
2830 return ch->character_type();
2833 int break_char_node::ends_sentence()
2835 return ch->ends_sentence();
2838 node *break_char_node::add_self(node *n, hyphen_list **p)
2840 assert((*p)->hyphenation_code == 0);
2841 if (break_code & 1) {
2842 if ((*p)->breakable || break_code & 4) {
2843 n = new space_node(H0, col, n);
2849 if (break_code & 2) {
2850 if ((*p)->breakable || break_code & 4) {
2851 n = new space_node(H0, col, n);
2855 hyphen_list *pp = *p;
2861 hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail, int *)
2863 return new hyphen_list(0, tail);
2866 hyphenation_type break_char_node::get_hyphenation_type()
2868 return HYPHEN_MIDDLE;
2871 void break_char_node::ascii_print(ascii_output_file *ascii)
2873 ch->ascii_print(ascii);
2876 int break_char_node::overlaps_vertically()
2878 return ch->overlaps_vertically();
2881 int break_char_node::overlaps_horizontally()
2883 return ch->overlaps_horizontally();
2886 units break_char_node::size()
2891 tfont *break_char_node::get_tfont()
2893 return ch->get_tfont();
2896 node *extra_size_node::copy()
2898 return new extra_size_node(n, state, div_nest_level);
2901 extra_size_node::extra_size_node(vunits i, statem *s, int pop)
2902 : node(0, s, pop), n(i)
2906 extra_size_node::extra_size_node(vunits i)
2911 node *vertical_size_node::copy()
2913 return new vertical_size_node(n, state, div_nest_level);
2916 vertical_size_node::vertical_size_node(vunits i, statem *s, int pop)
2917 : node(0, s, pop), n(i)
2921 vertical_size_node::vertical_size_node(vunits i)
2926 node *hmotion_node::copy()
2928 return new hmotion_node(n, was_tab, unformat, col, state, div_nest_level);
2931 node *space_char_hmotion_node::copy()
2933 return new space_char_hmotion_node(n, col, state, div_nest_level);
2936 vmotion_node::vmotion_node(vunits i, color *c)
2941 vmotion_node::vmotion_node(vunits i, color *c, statem *s, int pop)
2942 : node(0, s, pop), n(i), col(c)
2946 node *vmotion_node::copy()
2948 return new vmotion_node(n, col, state, div_nest_level);
2951 node *dummy_node::copy()
2953 return new dummy_node;
2956 node *transparent_dummy_node::copy()
2958 return new transparent_dummy_node;
2961 hline_node::~hline_node()
2967 hline_node::hline_node(hunits i, node *c, node *nxt)
2968 : node(nxt), x(i), n(c)
2972 hline_node::hline_node(hunits i, node *c, statem *s, int pop, node *nxt)
2973 : node(nxt, s, pop), x(i), n(c)
2977 node *hline_node::copy()
2979 return new hline_node(x, n ? n->copy() : 0, state, div_nest_level);
2982 hunits hline_node::width()
2984 return x < H0 ? H0 : x;
2987 vline_node::vline_node(vunits i, node *c, node *nxt)
2988 : node(nxt), x(i), n(c)
2992 vline_node::vline_node(vunits i, node *c, statem *s, int pop, node *nxt)
2993 : node(nxt, s, pop), x(i), n(c)
2997 vline_node::~vline_node()
3003 node *vline_node::copy()
3005 return new vline_node(x, n ? n->copy() : 0, state, div_nest_level);
3008 hunits vline_node::width()
3010 return n == 0 ? H0 : n->width();
3013 zero_width_node::zero_width_node(node *nd, statem *s, int pop)
3014 : node(0, s, pop), n(nd)
3018 zero_width_node::zero_width_node(node *nd)
3023 zero_width_node::~zero_width_node()
3025 delete_node_list(n);
3028 node *zero_width_node::copy()
3030 return new zero_width_node(copy_node_list(n), state, div_nest_level);
3033 int node_list_character_type(node *p)
3036 for (; p; p = p->next)
3037 t |= p->character_type();
3041 int zero_width_node::character_type()
3043 return node_list_character_type(n);
3046 void node_list_vertical_extent(node *p, vunits *min, vunits *max)
3050 vunits cur_vpos = V0;
3052 for (; p; p = p->next) {
3053 p->vertical_extent(&v1, &v2);
3060 cur_vpos += p->vertical_width();
3064 void zero_width_node::vertical_extent(vunits *min, vunits *max)
3066 node_list_vertical_extent(n, min, max);
3069 overstrike_node::overstrike_node()
3070 : list(0), max_width(H0)
3074 overstrike_node::overstrike_node(statem *s, int pop)
3075 : node(0, s, pop), list(0), max_width(H0)
3079 overstrike_node::~overstrike_node()
3081 delete_node_list(list);
3084 node *overstrike_node::copy()
3086 overstrike_node *on = new overstrike_node(state, div_nest_level);
3087 for (node *tem = list; tem; tem = tem->next)
3088 on->overstrike(tem->copy());
3092 void overstrike_node::overstrike(node *n)
3096 hunits w = n->width();
3100 for (p = &list; *p; p = &(*p)->next)
3106 hunits overstrike_node::width()
3111 bracket_node::bracket_node()
3112 : list(0), max_width(H0)
3116 bracket_node::bracket_node(statem *s, int pop)
3117 : node(0, s, pop), list(0), max_width(H0)
3121 bracket_node::~bracket_node()
3123 delete_node_list(list);
3126 node *bracket_node::copy()
3128 bracket_node *on = new bracket_node(state, div_nest_level);
3129 node *last_node = 0;
3133 for (tem = list; tem; tem = tem->next) {
3135 tem->next->last = tem;
3138 for (tem = last_node; tem; tem = tem->last)
3139 on->bracket(tem->copy());
3143 void bracket_node::bracket(node *n)
3147 hunits w = n->width();
3154 hunits bracket_node::width()
3164 int node::merge_space(hunits, hunits, hunits)
3170 space_node *space_node::free_list = 0;
3172 void *space_node::operator new(size_t n)
3174 assert(n == sizeof(space_node));
3176 free_list = (space_node *)new char[sizeof(space_node)*BLOCK];
3177 for (int i = 0; i < BLOCK - 1; i++)
3178 free_list[i].next = free_list + i + 1;
3179 free_list[BLOCK-1].next = 0;
3181 space_node *p = free_list;
3182 free_list = (space_node *)(free_list->next);
3187 inline void space_node::operator delete(void *p)
3190 ((space_node *)p)->next = free_list;
3191 free_list = (space_node *)p;
3196 space_node::space_node(hunits nn, color *c, node *p)
3197 : node(p, 0, 0), n(nn), set(0), was_escape_colon(0), col(c)
3201 space_node::space_node(hunits nn, color *c, statem *s, int pop, node *p)
3202 : node(p, s, pop), n(nn), set(0), was_escape_colon(0), col(c)
3206 space_node::space_node(hunits nn, int s, int flag, color *c, statem *st,
3208 : node(p, st, pop), n(nn), set(s), was_escape_colon(flag), col(c)
3213 space_node::~space_node()
3218 node *space_node::copy()
3220 return new space_node(n, set, was_escape_colon, col, state, div_nest_level);
3223 int space_node::force_tprint()
3228 int space_node::is_tag()
3233 int space_node::nspaces()
3238 int space_node::merge_space(hunits h, hunits, hunits)
3244 hunits space_node::width()
3249 void node::spread_space(int*, hunits*)
3253 void space_node::spread_space(int *n_spaces, hunits *desired_space)
3256 assert(*n_spaces > 0);
3257 if (*n_spaces == 1) {
3258 n += *desired_space;
3259 *desired_space = H0;
3262 hunits extra = *desired_space / *n_spaces;
3263 *desired_space -= extra;
3271 void node::freeze_space()
3275 void space_node::freeze_space()
3280 void node::is_escape_colon()
3284 void space_node::is_escape_colon()
3286 was_escape_colon = 1;
3289 diverted_space_node::diverted_space_node(vunits d, statem *s, int pop,
3291 : node(p, s, pop), n(d)
3295 diverted_space_node::diverted_space_node(vunits d, node *p)
3300 node *diverted_space_node::copy()
3302 return new diverted_space_node(n, state, div_nest_level);
3305 diverted_copy_file_node::diverted_copy_file_node(symbol s, statem *st,
3307 : node(p, st, pop), filename(s)
3311 diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p)
3312 : node(p), filename(s)
3316 node *diverted_copy_file_node::copy()
3318 return new diverted_copy_file_node(filename, state, div_nest_level);
3321 int node::ends_sentence()
3326 int kern_pair_node::ends_sentence()
3328 switch (n2->ends_sentence()) {
3338 return n1->ends_sentence();
3341 int node_list_ends_sentence(node *n)
3343 for (; n != 0; n = n->next)
3344 switch (n->ends_sentence()) {
3357 int dbreak_node::ends_sentence()
3359 return node_list_ends_sentence(none);
3362 int node::overlaps_horizontally()
3367 int node::overlaps_vertically()
3372 int node::discardable()
3377 int space_node::discardable()
3382 vunits node::vertical_width()
3387 vunits vline_node::vertical_width()
3392 vunits vmotion_node::vertical_width()
3397 int node::set_unformat_flag()
3402 int node::character_type()
3407 hunits node::subscript_correction()
3412 hunits node::italic_correction()
3417 hunits node::left_italic_correction()
3427 /* vertical_extent methods */
3429 void node::vertical_extent(vunits *min, vunits *max)
3431 vunits v = vertical_width();
3442 void vline_node::vertical_extent(vunits *min, vunits *max)
3445 node::vertical_extent(min, max);
3448 n->vertical_extent(&cmin, &cmax);
3449 vunits h = n->size();
3456 // we print the first character and then move up, so
3458 // we print the last character and then move up h
3471 // we move down by h and then print the first character, so
3481 /* ascii_print methods */
3483 static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n)
3487 ascii_print_reverse_node_list(ascii, n->next);
3488 n->ascii_print(ascii);
3491 void dbreak_node::ascii_print(ascii_output_file *ascii)
3493 ascii_print_reverse_node_list(ascii, none);
3496 void kern_pair_node::ascii_print(ascii_output_file *ascii)
3498 n1->ascii_print(ascii);
3499 n2->ascii_print(ascii);
3502 void node::ascii_print(ascii_output_file *)
3506 void space_node::ascii_print(ascii_output_file *ascii)
3512 void hmotion_node::ascii_print(ascii_output_file *ascii)
3514 // this is pretty arbitrary
3515 if (n >= points_to_units(2))
3519 void space_char_hmotion_node::ascii_print(ascii_output_file *ascii)
3524 /* asciify methods */
3526 void node::asciify(macro *m)
3531 void glyph_node::asciify(macro *m)
3533 unsigned char c = ci->get_asciify_code();
3535 c = ci->get_ascii_code();
3544 void kern_pair_node::asciify(macro *m)
3552 static void asciify_reverse_node_list(macro *m, node *n)
3556 asciify_reverse_node_list(m, n->next);
3560 void dbreak_node::asciify(macro *m)
3562 asciify_reverse_node_list(m, none);
3567 void ligature_node::asciify(macro *m)
3575 void break_char_node::asciify(macro *m)
3582 void italic_corrected_node::asciify(macro *m)
3589 void left_italic_corrected_node::asciify(macro *m)
3598 void hmotion_node::asciify(macro *m)
3608 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3611 : hmotion_node(i, c, s, pop, nxt)
3615 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3617 : hmotion_node(i, c, 0, 0, nxt)
3621 void space_char_hmotion_node::asciify(macro *m)
3623 m->append(ESCAPE_SPACE);
3627 void space_node::asciify(macro *m)
3629 if (was_escape_colon) {
3630 m->append(ESCAPE_COLON);
3637 void word_space_node::asciify(macro *m)
3639 for (width_list *w = orig_width; w; w = w->next)
3644 void unbreakable_space_node::asciify(macro *m)
3646 m->append(ESCAPE_TILDE);
3650 void line_start_node::asciify(macro *)
3655 void vertical_size_node::asciify(macro *)
3660 breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/,
3661 breakpoint *rest, int /*is_inner*/)
3671 breakpoint *space_node::get_breakpoints(hunits wd, int ns,
3672 breakpoint *rest, int is_inner)
3674 if (next && next->discardable())
3676 breakpoint *bp = new breakpoint;
3683 bp->index = rest->index + 1;
3693 int space_node::nbreaks()
3695 if (next && next->discardable())
3701 static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp,
3702 int ns, breakpoint *rest)
3705 rest = p->get_breakpoints(*widthp,
3707 node_list_get_breakpoints(p->next, widthp, ns,
3710 *widthp += p->width();
3715 breakpoint *dbreak_node::get_breakpoints(hunits wd, int ns,
3716 breakpoint *rest, int is_inner)
3718 breakpoint *bp = new breakpoint;
3721 for (node *tem = pre; tem != 0; tem = tem->next)
3722 bp->width += tem->width();
3727 bp->index = rest->index + 1;
3734 return node_list_get_breakpoints(none, &wd, ns, bp);
3737 int dbreak_node::nbreaks()
3740 for (node *tem = none; tem != 0; tem = tem->next)
3741 i += tem->nbreaks();
3745 void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/)
3750 void space_node::split(int where, node **pre, node **post)
3758 static void node_list_split(node *p, int *wherep, node **prep, node **postp)
3762 int nb = p->nbreaks();
3763 node_list_split(p->next, wherep, prep, postp);
3768 else if (*wherep < nb) {
3770 p->split(*wherep, prep, postp);
3779 void dbreak_node::split(int where, node **prep, node **postp)
3789 for (tem = pre; tem->next != 0; tem = tem->next)
3800 node_list_split(none, &where, prep, postp);
3806 hyphenation_type node::get_hyphenation_type()
3808 return HYPHEN_BOUNDARY;
3811 hyphenation_type dbreak_node::get_hyphenation_type()
3813 return HYPHEN_INHIBIT;
3816 hyphenation_type kern_pair_node::get_hyphenation_type()
3818 return HYPHEN_MIDDLE;
3821 hyphenation_type dummy_node::get_hyphenation_type()
3823 return HYPHEN_MIDDLE;
3826 hyphenation_type transparent_dummy_node::get_hyphenation_type()
3828 return HYPHEN_MIDDLE;
3831 hyphenation_type hmotion_node::get_hyphenation_type()
3833 return HYPHEN_MIDDLE;
3836 hyphenation_type space_char_hmotion_node::get_hyphenation_type()
3838 return HYPHEN_MIDDLE;
3841 hyphenation_type overstrike_node::get_hyphenation_type()
3843 return HYPHEN_MIDDLE;
3846 hyphenation_type space_node::get_hyphenation_type()
3848 if (was_escape_colon)
3849 return HYPHEN_MIDDLE;
3850 return HYPHEN_BOUNDARY;
3853 hyphenation_type unbreakable_space_node::get_hyphenation_type()
3855 return HYPHEN_MIDDLE;
3858 int node::interpret(macro *)
3863 special_node::special_node(const macro &m, int n)
3864 : mac(m), no_init_string(n)
3866 font_size fs = curenv->get_font_size();
3867 int char_height = curenv->get_char_height();
3868 int char_slant = curenv->get_char_slant();
3869 int fontno = env_definite_font(curenv);
3870 tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno);
3871 if (curenv->is_composite())
3872 tf = tf->get_plain();
3873 gcol = curenv->get_glyph_color();
3874 fcol = curenv->get_fill_color();
3878 special_node::special_node(const macro &m, tfont *t,
3879 color *gc, color *fc,
3882 : node(0, s, pop), mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n)
3887 int special_node::same(node *n)
3889 return mac == ((special_node *)n)->mac
3890 && tf == ((special_node *)n)->tf
3891 && gcol == ((special_node *)n)->gcol
3892 && fcol == ((special_node *)n)->fcol
3893 && no_init_string == ((special_node *)n)->no_init_string;
3896 const char *special_node::type()
3898 return "special_node";
3901 int special_node::ends_sentence()
3906 int special_node::force_tprint()
3911 int special_node::is_tag()
3916 node *special_node::copy()
3918 return new special_node(mac, tf, gcol, fcol, state, div_nest_level,
3922 void special_node::tprint_start(troff_output_file *out)
3924 out->start_special(tf, gcol, fcol, no_init_string);
3927 void special_node::tprint_char(troff_output_file *out, unsigned char c)
3929 out->special_char(c);
3932 void special_node::tprint_end(troff_output_file *out)
3937 tfont *special_node::get_tfont()
3944 suppress_node::suppress_node(int on_or_off, int issue_limits)
3945 : is_on(on_or_off), emit_limits(issue_limits), filename(0), position(0),
3950 suppress_node::suppress_node(symbol f, char p, int id)
3951 : is_on(2), emit_limits(0), filename(f), position(p), image_id(id)
3956 suppress_node::suppress_node(int issue_limits, int on_or_off,
3957 symbol f, char p, int id,
3959 : node(0, s, pop), is_on(on_or_off), emit_limits(issue_limits), filename(f),
3960 position(p), image_id(id)
3964 int suppress_node::same(node *n)
3966 return ((is_on == ((suppress_node *)n)->is_on)
3967 && (emit_limits == ((suppress_node *)n)->emit_limits)
3968 && (filename == ((suppress_node *)n)->filename)
3969 && (position == ((suppress_node *)n)->position)
3970 && (image_id == ((suppress_node *)n)->image_id));
3973 const char *suppress_node::type()
3975 return "suppress_node";
3978 node *suppress_node::copy()
3980 return new suppress_node(emit_limits, is_on, filename, position, image_id,
3981 state, div_nest_level);
3986 tag_node::tag_node()
3992 tag_node::tag_node(string s, int delay)
3993 : tag_string(s), delayed(delay)
3995 is_special = !delay;
3998 tag_node::tag_node(string s, statem *st, int pop, int delay)
3999 : node(0, st, pop), tag_string(s), delayed(delay)
4001 is_special = !delay;
4004 node *tag_node::copy()
4006 return new tag_node(tag_string, state, div_nest_level, delayed);
4009 void tag_node::tprint(troff_output_file *out)
4012 out->add_to_tag_list(tag_string);
4014 out->state.add_tag(out->fp, tag_string);
4017 int tag_node::same(node *nd)
4019 return tag_string == ((tag_node *)nd)->tag_string
4020 && delayed == ((tag_node *)nd)->delayed;
4023 const char *tag_node::type()
4028 int tag_node::force_tprint()
4033 int tag_node::is_tag()
4038 int tag_node::ends_sentence()
4043 int get_reg_int(const char *p)
4045 reg *r = (reg *)number_reg_dictionary.lookup(p);
4047 if (r && (r->get_value(&prev_value)))
4048 return (int)prev_value;
4050 warning(WARN_REG, "number register `%1' not defined", p);
4054 const char *get_reg_str(const char *p)
4056 reg *r = (reg *)number_reg_dictionary.lookup(p);
4058 return r->get_string();
4060 warning(WARN_REG, "register `%1' not defined", p);
4064 void suppress_node::put(troff_output_file *out, const char *s)
4067 while (s[i] != (char)0) {
4068 out->special_char(s[i]);
4074 * We need to remember the start of the image and its name.
4077 static char last_position = 0;
4078 static const char *last_image_filename = 0;
4079 static int last_image_id = 0;
4081 inline int min(int a, int b)
4083 return a < b ? a : b;
4087 * tprint - if (is_on == 2)
4088 * remember current position (l, r, c, i) and filename
4094 * emit postscript bounds for image
4096 * if (suppress boolean differs from current state)
4099 * record current page
4100 * set low water mark.
4103 void suppress_node::tprint(troff_output_file *out)
4105 int current_page = topdiv->get_page_number();
4106 // firstly check to see whether this suppress node contains
4107 // an image filename & position.
4109 // remember position and filename
4110 last_position = position;
4111 char *tem = (char *)last_image_filename;
4112 last_image_filename = strsave(filename.contents());
4115 last_image_id = image_id;
4116 // printf("start of image and page = %d\n", current_page);
4119 // now check whether the suppress node requires us to issue limits.
4122 // remember that the filename will contain a %d in which the
4123 // last_image_id is placed
4124 if (last_image_filename == (char *) 0)
4127 sprintf(name, last_image_filename, last_image_id);
4129 switch (last_position) {
4131 out->start_special();
4132 put(out, "devtag:.centered-image");
4135 out->start_special();
4136 put(out, "devtag:.right-image");
4139 out->start_special();
4140 put(out, "devtag:.left-image");
4148 out->start_special();
4149 put(out, "devtag:.auto-image ");
4154 // postscript (or other device)
4155 if (suppress_start_page > 0 && current_page != suppress_start_page)
4156 error("suppression limit registers span more than one page;\n"
4157 "image description %1 will be wrong", image_no);
4158 // if (topdiv->get_page_number() != suppress_start_page)
4159 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
4160 // topdiv->get_page_number(), suppress_start_page);
4162 // remember that the filename will contain a %d in which the
4163 // image_no is placed
4165 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
4166 topdiv->get_page_number(),
4167 get_reg_int("opminx"), get_reg_int("opminy"),
4168 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
4169 // page offset + line length
4170 get_reg_int(".o") + get_reg_int(".l"),
4171 name, hresolution, vresolution, get_reg_str(".F"));
4178 // lastly we reset the output registers
4179 reset_output_registers();
4183 suppress_start_page = current_page;
4188 int suppress_node::force_tprint()
4193 int suppress_node::is_tag()
4198 hunits suppress_node::width()
4203 /* composite_node */
4205 class composite_node : public charinfo_node {
4209 composite_node(node *, charinfo *, tfont *, statem *, int, node * = 0);
4213 node *last_char_node();
4215 void tprint(troff_output_file *);
4216 hyphenation_type get_hyphenation_type();
4217 void ascii_print(ascii_output_file *);
4218 void asciify(macro *);
4219 hyphen_list *get_hyphen_list(hyphen_list *, int *);
4220 node *add_self(node *, hyphen_list **);
4226 void vertical_extent(vunits *, vunits *);
4227 vunits vertical_width();
4230 composite_node::composite_node(node *p, charinfo *c, tfont *t, statem *s,
4232 : charinfo_node(c, s, pop, x), n(p), tf(t)
4236 composite_node::~composite_node()
4238 delete_node_list(n);
4241 node *composite_node::copy()
4243 return new composite_node(copy_node_list(n), ci, tf, state, div_nest_level);
4246 hunits composite_node::width()
4249 if (tf->get_constant_space(&x))
4252 for (node *tem = n; tem; tem = tem->next)
4255 if (tf->get_bold(&offset))
4257 x += tf->get_track_kern();
4261 node *composite_node::last_char_node()
4266 vunits composite_node::vertical_width()
4269 for (node *tem = n; tem; tem = tem->next)
4270 v += tem->vertical_width();
4274 units composite_node::size()
4276 return tf->get_size().to_units();
4279 hyphenation_type composite_node::get_hyphenation_type()
4281 return HYPHEN_MIDDLE;
4284 void composite_node::asciify(macro *m)
4286 unsigned char c = ci->get_asciify_code();
4288 c = ci->get_ascii_code();
4297 void composite_node::ascii_print(ascii_output_file *ascii)
4299 unsigned char c = ci->get_ascii_code();
4303 ascii->outs(ci->nm.contents());
4307 hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail, int *count)
4310 return new hyphen_list(ci->get_hyphenation_code(), tail);
4313 node *composite_node::add_self(node *nn, hyphen_list **p)
4315 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
4319 nn = nn->add_discretionary_hyphen();
4320 hyphen_list *pp = *p;
4326 tfont *composite_node::get_tfont()
4331 node *reverse_node_list(node *n)
4343 void composite_node::vertical_extent(vunits *minimum, vunits *maximum)
4345 n = reverse_node_list(n);
4346 node_list_vertical_extent(n, minimum, maximum);
4347 n = reverse_node_list(n);
4350 width_list::width_list(hunits w, hunits s)
4351 : width(w), sentence_width(s), next(0)
4355 width_list::width_list(width_list *w)
4356 : width(w->width), sentence_width(w->sentence_width), next(0)
4360 word_space_node::word_space_node(hunits d, color *c, width_list *w, node *x)
4361 : space_node(d, c, x), orig_width(w), unformat(0)
4365 word_space_node::word_space_node(hunits d, int s, color *c, width_list *w,
4366 int flag, statem *st, int pop, node *x)
4367 : space_node(d, s, 0, c, st, pop, x), orig_width(w), unformat(flag)
4371 word_space_node::~word_space_node()
4373 width_list *w = orig_width;
4375 width_list *tmp = w;
4381 node *word_space_node::copy()
4383 assert(orig_width != 0);
4384 width_list *w_old_curr = orig_width;
4385 width_list *w_new_curr = new width_list(w_old_curr);
4386 width_list *w_new = w_new_curr;
4387 w_old_curr = w_old_curr->next;
4388 while (w_old_curr != 0) {
4389 w_new_curr->next = new width_list(w_old_curr);
4390 w_new_curr = w_new_curr->next;
4391 w_old_curr = w_old_curr->next;
4393 return new word_space_node(n, set, col, w_new, unformat, state,
4397 int word_space_node::set_unformat_flag()
4403 void word_space_node::tprint(troff_output_file *out)
4405 out->fill_color(col);
4410 int word_space_node::merge_space(hunits h, hunits sw, hunits ssw)
4413 assert(orig_width != 0);
4414 width_list *w = orig_width;
4415 for (; w->next; w = w->next)
4417 w->next = new width_list(sw, ssw);
4421 unbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x)
4422 : word_space_node(d, c, 0, x)
4426 unbreakable_space_node::unbreakable_space_node(hunits d, int s,
4427 color *c, statem *st, int pop,
4429 : word_space_node(d, s, c, 0, 0, st, pop, x)
4433 node *unbreakable_space_node::copy()
4435 return new unbreakable_space_node(n, set, col, state, div_nest_level);
4438 int unbreakable_space_node::force_tprint()
4443 int unbreakable_space_node::is_tag()
4448 breakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
4449 breakpoint *rest, int)
4454 int unbreakable_space_node::nbreaks()
4459 void unbreakable_space_node::split(int, node **, node **)
4464 int unbreakable_space_node::merge_space(hunits, hunits, hunits)
4473 draw_node::draw_node(char c, hvpair *p, int np, font_size s,
4474 color *gc, color *fc)
4475 : npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4477 point = new hvpair[npoints];
4478 for (int i = 0; i < npoints; i++)
4482 draw_node::draw_node(char c, hvpair *p, int np, font_size s,
4483 color *gc, color *fc, statem *st, int pop)
4484 : node(0, st, pop), npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4486 point = new hvpair[npoints];
4487 for (int i = 0; i < npoints; i++)
4491 int draw_node::same(node *n)
4493 draw_node *nd = (draw_node *)n;
4494 if (code != nd->code || npoints != nd->npoints || sz != nd->sz
4495 || gcol != nd->gcol || fcol != nd->fcol)
4497 for (int i = 0; i < npoints; i++)
4498 if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
4503 const char *draw_node::type()
4508 int draw_node::force_tprint()
4513 int draw_node::is_tag()
4518 draw_node::~draw_node()
4524 hunits draw_node::width()
4527 for (int i = 0; i < npoints; i++)
4532 vunits draw_node::vertical_width()
4537 for (int i = 0; i < npoints; i++)
4542 node *draw_node::copy()
4544 return new draw_node(code, point, npoints, sz, gcol, fcol, state,
4548 void draw_node::tprint(troff_output_file *out)
4550 out->draw(code, point, npoints, sz, gcol, fcol);
4553 /* tprint methods */
4555 void glyph_node::tprint(troff_output_file *out)
4557 tfont *ptf = tf->get_plain();
4559 out->put_char_width(ci, ptf, gcol, fcol, width(), H0);
4562 int bold = tf->get_bold(&offset);
4563 hunits w = ptf->get_width(ci);
4566 int cs = tf->get_constant_space(&x);
4576 k = tf->get_track_kern();
4578 out->put_char(ci, ptf, gcol, fcol);
4581 out->put_char_width(ci, ptf, gcol, fcol, w, k);
4585 void glyph_node::zero_width_tprint(troff_output_file *out)
4587 tfont *ptf = tf->get_plain();
4589 int bold = tf->get_bold(&offset);
4591 int cs = tf->get_constant_space(&x);
4593 x -= ptf->get_width(ci);
4599 out->put_char(ci, ptf, gcol, fcol);
4602 out->put_char(ci, ptf, gcol, fcol);
4603 out->right(-offset);
4609 void break_char_node::tprint(troff_output_file *t)
4614 void break_char_node::zero_width_tprint(troff_output_file *t)
4616 ch->zero_width_tprint(t);
4619 void hline_node::tprint(troff_output_file *out)
4629 hunits w = n->width();
4631 error("horizontal line drawing character must have positive width");
4642 out->right(xx - xx2);
4645 hunits rem = x - w*i;
4647 if (n->overlaps_horizontally()) {
4650 out->right(rem - w);
4660 void vline_node::tprint(troff_output_file *out)
4666 vunits h = n->size();
4667 int overlaps = n->overlaps_vertically();
4672 vunits rem = y - i*h;
4674 out->right(n->width());
4679 n->zero_width_tprint(out);
4683 n->zero_width_tprint(out);
4692 out->down(-h - rem);
4698 vunits rem = y - i*h;
4701 out->right(n->width());
4706 n->zero_width_tprint(out);
4709 n->zero_width_tprint(out);
4718 void zero_width_node::tprint(troff_output_file *out)
4723 n->zero_width_tprint(out);
4726 int hpos = out->get_hpos();
4727 int vpos = out->get_vpos();
4733 out->moveto(hpos, vpos);
4736 void overstrike_node::tprint(troff_output_file *out)
4739 for (node *tem = list; tem; tem = tem->next) {
4740 hunits x = (max_width - tem->width())/2;
4741 out->right(x - pos);
4743 tem->zero_width_tprint(out);
4745 out->right(max_width - pos);
4748 void bracket_node::tprint(troff_output_file *out)
4754 for (tem = list; tem; tem = tem->next)
4756 vunits h = list->size();
4757 vunits totalh = h*npieces;
4758 vunits y = (totalh - h)/2;
4760 for (tem = list; tem; tem = tem->next) {
4761 tem->zero_width_tprint(out);
4764 out->right(max_width);
4765 out->down(totalh - y);
4768 void node::tprint(troff_output_file *)
4772 void node::zero_width_tprint(troff_output_file *out)
4774 int hpos = out->get_hpos();
4775 int vpos = out->get_vpos();
4777 out->moveto(hpos, vpos);
4780 void space_node::tprint(troff_output_file *out)
4782 out->fill_color(col);
4786 void hmotion_node::tprint(troff_output_file *out)
4788 out->fill_color(col);
4792 void space_char_hmotion_node::tprint(troff_output_file *out)
4794 out->fill_color(col);
4796 // we emit the space width as a negative glyph index
4800 out->put(-n.to_units());
4806 void vmotion_node::tprint(troff_output_file *out)
4808 out->fill_color(col);
4812 void kern_pair_node::tprint(troff_output_file *out)
4819 static void tprint_reverse_node_list(troff_output_file *out, node *n)
4823 tprint_reverse_node_list(out, n->next);
4827 void dbreak_node::tprint(troff_output_file *out)
4829 tprint_reverse_node_list(out, none);
4832 void composite_node::tprint(troff_output_file *out)
4835 int is_bold = tf->get_bold(&bold_offset);
4836 hunits track_kern = tf->get_track_kern();
4837 hunits constant_space;
4838 int is_constant_spaced = tf->get_constant_space(&constant_space);
4840 if (is_constant_spaced) {
4842 for (node *tem = n; tem; tem = tem->next)
4851 int hpos = out->get_hpos();
4852 int vpos = out->get_vpos();
4853 tprint_reverse_node_list(out, n);
4854 out->moveto(hpos, vpos);
4855 out->right(bold_offset);
4857 tprint_reverse_node_list(out, n);
4858 if (is_constant_spaced)
4861 out->right(track_kern);
4864 node *make_composite_node(charinfo *s, environment *env)
4866 int fontno = env_definite_font(env);
4868 error("no current font");
4871 assert(fontno < font_table_size && font_table[fontno] != 0);
4872 node *n = charinfo_to_node_list(s, env);
4873 font_size fs = env->get_font_size();
4874 int char_height = env->get_char_height();
4875 int char_slant = env->get_char_slant();
4876 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
4878 if (env->is_composite())
4879 tf = tf->get_plain();
4880 return new composite_node(n, s, tf, 0, 0, 0);
4883 node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
4885 int fontno = env_definite_font(env);
4887 error("no current font");
4890 assert(fontno < font_table_size && font_table[fontno] != 0);
4892 int found = font_table[fontno]->contains(s);
4894 macro *mac = s->get_macro();
4895 if (mac && s->is_fallback())
4896 return make_composite_node(s, env);
4897 if (s->numbered()) {
4898 if (!no_error_message)
4899 warning(WARN_CHAR, "can't find numbered character %1",
4903 special_font_list *sf = font_table[fontno]->sf;
4904 while (sf != 0 && !found) {
4907 found = font_table[fn]->contains(s);
4911 symbol f = font_table[fontno]->get_name();
4912 string gl(f.contents());
4914 gl += s->nm.contents();
4916 charinfo *ci = get_charinfo(symbol(gl.contents()));
4917 if (ci && ci->get_macro())
4918 return make_composite_node(ci, env);
4921 sf = global_special_fonts;
4922 while (sf != 0 && !found) {
4925 found = font_table[fn]->contains(s);
4930 if (mac && s->is_special())
4931 return make_composite_node(s, env);
4933 for (fn = 0; fn < font_table_size; fn++)
4935 && font_table[fn]->is_special()
4936 && font_table[fn]->contains(s)) {
4942 if (!no_error_message && s->first_time_not_found()) {
4943 unsigned char input_code = s->get_ascii_code();
4944 if (input_code != 0) {
4945 if (csgraph(input_code))
4946 warning(WARN_CHAR, "can't find character `%1'", input_code);
4948 warning(WARN_CHAR, "can't find character with input code %1",
4951 else if (s->nm.contents()) {
4952 const char *nm = s->nm.contents();
4953 const char *backslash = (nm[1] == 0) ? "\\" : "";
4954 warning(WARN_CHAR, "can't find special character `%1%2'",
4961 font_size fs = env->get_font_size();
4962 int char_height = env->get_char_height();
4963 int char_slant = env->get_char_slant();
4964 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
4965 if (env->is_composite())
4966 tf = tf->get_plain();
4967 color *gcol = env->get_glyph_color();
4968 color *fcol = env->get_fill_color();
4969 return new glyph_node(s, tf, gcol, fcol, 0, 0);
4972 node *make_node(charinfo *ci, environment *env)
4974 switch (ci->get_special_translation()) {
4975 case charinfo::TRANSLATE_SPACE:
4976 return new space_char_hmotion_node(env->get_space_width(),
4977 env->get_fill_color());
4978 case charinfo::TRANSLATE_STRETCHABLE_SPACE:
4979 return new unbreakable_space_node(env->get_space_width(),
4980 env->get_fill_color());
4981 case charinfo::TRANSLATE_DUMMY:
4982 return new dummy_node;
4983 case charinfo::TRANSLATE_HYPHEN_INDICATOR:
4984 error("translation to \\% ignored in this context");
4987 charinfo *tem = ci->get_translation();
4990 macro *mac = ci->get_macro();
4991 if (mac && ci->is_normal())
4992 return make_composite_node(ci, env);
4994 return make_glyph_node(ci, env);
4997 int character_exists(charinfo *ci, environment *env)
4999 if (ci->get_special_translation() != charinfo::TRANSLATE_NONE)
5001 charinfo *tem = ci->get_translation();
5004 if (ci->get_macro())
5006 node *nd = make_glyph_node(ci, env, 1);
5014 node *node::add_char(charinfo *ci, environment *env,
5015 hunits *widthp, int *spacep, node **glyph_comp_np)
5018 switch (ci->get_special_translation()) {
5019 case charinfo::TRANSLATE_SPACE:
5020 res = new space_char_hmotion_node(env->get_space_width(),
5021 env->get_fill_color(), this);
5022 *widthp += res->width();
5024 case charinfo::TRANSLATE_STRETCHABLE_SPACE:
5025 res = new unbreakable_space_node(env->get_space_width(),
5026 env->get_fill_color(), this);
5027 res->freeze_space();
5028 *widthp += res->width();
5029 *spacep += res->nspaces();
5031 case charinfo::TRANSLATE_DUMMY:
5032 return new dummy_node(this);
5033 case charinfo::TRANSLATE_HYPHEN_INDICATOR:
5034 return add_discretionary_hyphen();
5036 charinfo *tem = ci->get_translation();
5039 macro *mac = ci->get_macro();
5040 if (mac && ci->is_normal()) {
5041 res = make_composite_node(ci, env);
5044 *widthp += res->width();
5046 *glyph_comp_np = res;
5050 *glyph_comp_np = res;
5055 node *gn = make_glyph_node(ci, env);
5059 hunits old_width = width();
5060 node *p = gn->merge_self(this);
5062 *widthp += gn->width();
5067 *widthp += p->width() - old_width;
5071 *glyph_comp_np = res;
5075 if (ci->can_break_before())
5077 if (ci->can_break_after())
5079 if (ci->ignore_hcodes())
5082 node *next1 = res->next;
5084 res = new break_char_node(res, break_code, env->get_fill_color(), next1);
5092 int same_node(node *n1, node *n2)
5096 return n1->type() == n2->type() && n1->same(n2);
5104 int same_node_list(node *n1, node *n2)
5107 if (n1->type() != n2->type() || !n1->same(n2))
5115 int extra_size_node::same(node *nd)
5117 return n == ((extra_size_node *)nd)->n;
5120 const char *extra_size_node::type()
5122 return "extra_size_node";
5125 int extra_size_node::force_tprint()
5130 int extra_size_node::is_tag()
5135 int vertical_size_node::same(node *nd)
5137 return n == ((vertical_size_node *)nd)->n;
5140 const char *vertical_size_node::type()
5142 return "vertical_size_node";
5145 int vertical_size_node::set_unformat_flag()
5150 int vertical_size_node::force_tprint()
5155 int vertical_size_node::is_tag()
5160 int hmotion_node::same(node *nd)
5162 return n == ((hmotion_node *)nd)->n
5163 && col == ((hmotion_node *)nd)->col;
5166 const char *hmotion_node::type()
5168 return "hmotion_node";
5171 int hmotion_node::set_unformat_flag()
5177 int hmotion_node::force_tprint()
5182 int hmotion_node::is_tag()
5187 node *hmotion_node::add_self(node *nd, hyphen_list **p)
5190 hyphen_list *pp = *p;
5196 hyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail, int *)
5198 return new hyphen_list(0, tail);
5201 int space_char_hmotion_node::same(node *nd)
5203 return n == ((space_char_hmotion_node *)nd)->n
5204 && col == ((space_char_hmotion_node *)nd)->col;
5207 const char *space_char_hmotion_node::type()
5209 return "space_char_hmotion_node";
5212 int space_char_hmotion_node::force_tprint()
5217 int space_char_hmotion_node::is_tag()
5222 node *space_char_hmotion_node::add_self(node *nd, hyphen_list **p)
5225 hyphen_list *pp = *p;
5231 hyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail,
5234 return new hyphen_list(0, tail);
5237 int vmotion_node::same(node *nd)
5239 return n == ((vmotion_node *)nd)->n
5240 && col == ((vmotion_node *)nd)->col;
5243 const char *vmotion_node::type()
5245 return "vmotion_node";
5248 int vmotion_node::force_tprint()
5253 int vmotion_node::is_tag()
5258 int hline_node::same(node *nd)
5260 return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
5263 const char *hline_node::type()
5265 return "hline_node";
5268 int hline_node::force_tprint()
5273 int hline_node::is_tag()
5278 int vline_node::same(node *nd)
5280 return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
5283 const char *vline_node::type()
5285 return "vline_node";
5288 int vline_node::force_tprint()
5293 int vline_node::is_tag()
5298 int dummy_node::same(node * /*nd*/)
5303 const char *dummy_node::type()
5305 return "dummy_node";
5308 int dummy_node::force_tprint()
5313 int dummy_node::is_tag()
5318 int transparent_dummy_node::same(node * /*nd*/)
5323 const char *transparent_dummy_node::type()
5325 return "transparent_dummy_node";
5328 int transparent_dummy_node::force_tprint()
5333 int transparent_dummy_node::is_tag()
5338 int transparent_dummy_node::ends_sentence()
5343 int zero_width_node::same(node *nd)
5345 return same_node_list(n, ((zero_width_node *)nd)->n);
5348 const char *zero_width_node::type()
5350 return "zero_width_node";
5353 int zero_width_node::force_tprint()
5358 int zero_width_node::is_tag()
5363 int italic_corrected_node::same(node *nd)
5365 return (x == ((italic_corrected_node *)nd)->x
5366 && same_node(n, ((italic_corrected_node *)nd)->n));
5369 const char *italic_corrected_node::type()
5371 return "italic_corrected_node";
5374 int italic_corrected_node::force_tprint()
5379 int italic_corrected_node::is_tag()
5384 left_italic_corrected_node::left_italic_corrected_node(node *xx)
5389 left_italic_corrected_node::left_italic_corrected_node(statem *s, int pop,
5391 : node(xx, s, pop), n(0)
5395 left_italic_corrected_node::~left_italic_corrected_node()
5400 node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn)
5403 hunits lic = gn->left_italic_correction();
5404 if (!lic.is_zero()) {
5411 node *nd = n->merge_glyph_node(gn);
5414 x = n->left_italic_correction();
5421 node *left_italic_corrected_node::copy()
5423 left_italic_corrected_node *nd =
5424 new left_italic_corrected_node(state, div_nest_level);
5432 void left_italic_corrected_node::tprint(troff_output_file *out)
5440 const char *left_italic_corrected_node::type()
5442 return "left_italic_corrected_node";
5445 int left_italic_corrected_node::force_tprint()
5450 int left_italic_corrected_node::is_tag()
5455 int left_italic_corrected_node::same(node *nd)
5457 return (x == ((left_italic_corrected_node *)nd)->x
5458 && same_node(n, ((left_italic_corrected_node *)nd)->n));
5461 void left_italic_corrected_node::ascii_print(ascii_output_file *out)
5464 n->ascii_print(out);
5467 hunits left_italic_corrected_node::width()
5469 return n ? n->width() + x : H0;
5472 void left_italic_corrected_node::vertical_extent(vunits *minimum,
5476 n->vertical_extent(minimum, maximum);
5478 node::vertical_extent(minimum, maximum);
5481 hunits left_italic_corrected_node::skew()
5483 return n ? n->skew() + x/2 : H0;
5486 hunits left_italic_corrected_node::subscript_correction()
5488 return n ? n->subscript_correction() : H0;
5491 hunits left_italic_corrected_node::italic_correction()
5493 return n ? n->italic_correction() : H0;
5496 int left_italic_corrected_node::ends_sentence()
5498 return n ? n->ends_sentence() : 0;
5501 int left_italic_corrected_node::overlaps_horizontally()
5503 return n ? n->overlaps_horizontally() : 0;
5506 int left_italic_corrected_node::overlaps_vertically()
5508 return n ? n->overlaps_vertically() : 0;
5511 node *left_italic_corrected_node::last_char_node()
5513 return n ? n->last_char_node() : 0;
5516 tfont *left_italic_corrected_node::get_tfont()
5518 return n ? n->get_tfont() : 0;
5521 hyphenation_type left_italic_corrected_node::get_hyphenation_type()
5524 return n->get_hyphenation_type();
5526 return HYPHEN_MIDDLE;
5529 hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail,
5532 return n ? n->get_hyphen_list(tail, count) : tail;
5535 node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p)
5538 nd = new left_italic_corrected_node(state, div_nest_level, nd);
5539 nd = n->add_self(nd, p);
5550 int left_italic_corrected_node::character_type()
5552 return n ? n->character_type() : 0;
5555 int overstrike_node::same(node *nd)
5557 return same_node_list(list, ((overstrike_node *)nd)->list);
5560 const char *overstrike_node::type()
5562 return "overstrike_node";
5565 int overstrike_node::force_tprint()
5570 int overstrike_node::is_tag()
5575 node *overstrike_node::add_self(node *n, hyphen_list **p)
5578 hyphen_list *pp = *p;
5584 hyphen_list *overstrike_node::get_hyphen_list(hyphen_list *tail, int *)
5586 return new hyphen_list(0, tail);
5589 int bracket_node::same(node *nd)
5591 return same_node_list(list, ((bracket_node *)nd)->list);
5594 const char *bracket_node::type()
5596 return "bracket_node";
5599 int bracket_node::force_tprint()
5604 int bracket_node::is_tag()
5609 int composite_node::same(node *nd)
5611 return ci == ((composite_node *)nd)->ci
5612 && same_node_list(n, ((composite_node *)nd)->n);
5615 const char *composite_node::type()
5617 return "composite_node";
5620 int composite_node::force_tprint()
5625 int composite_node::is_tag()
5630 int glyph_node::same(node *nd)
5632 return ci == ((glyph_node *)nd)->ci
5633 && tf == ((glyph_node *)nd)->tf
5634 && gcol == ((glyph_node *)nd)->gcol
5635 && fcol == ((glyph_node *)nd)->fcol;
5638 const char *glyph_node::type()
5640 return "glyph_node";
5643 int glyph_node::force_tprint()
5648 int glyph_node::is_tag()
5653 int ligature_node::same(node *nd)
5655 return (same_node(n1, ((ligature_node *)nd)->n1)
5656 && same_node(n2, ((ligature_node *)nd)->n2)
5657 && glyph_node::same(nd));
5660 const char *ligature_node::type()
5662 return "ligature_node";
5665 int ligature_node::force_tprint()
5670 int ligature_node::is_tag()
5675 int kern_pair_node::same(node *nd)
5677 return (amount == ((kern_pair_node *)nd)->amount
5678 && same_node(n1, ((kern_pair_node *)nd)->n1)
5679 && same_node(n2, ((kern_pair_node *)nd)->n2));
5682 const char *kern_pair_node::type()
5684 return "kern_pair_node";
5687 int kern_pair_node::force_tprint()
5692 int kern_pair_node::is_tag()
5697 int dbreak_node::same(node *nd)
5699 return (same_node_list(none, ((dbreak_node *)nd)->none)
5700 && same_node_list(pre, ((dbreak_node *)nd)->pre)
5701 && same_node_list(post, ((dbreak_node *)nd)->post));
5704 const char *dbreak_node::type()
5706 return "dbreak_node";
5709 int dbreak_node::force_tprint()
5714 int dbreak_node::is_tag()
5719 int break_char_node::same(node *nd)
5721 return break_code == ((break_char_node *)nd)->break_code
5722 && col == ((break_char_node *)nd)->col
5723 && same_node(ch, ((break_char_node *)nd)->ch);
5726 const char *break_char_node::type()
5728 return "break_char_node";
5731 int break_char_node::force_tprint()
5736 int break_char_node::is_tag()
5741 int line_start_node::same(node * /*nd*/)
5746 const char *line_start_node::type()
5748 return "line_start_node";
5751 int line_start_node::force_tprint()
5756 int line_start_node::is_tag()
5761 int space_node::same(node *nd)
5763 return n == ((space_node *)nd)->n
5764 && set == ((space_node *)nd)->set
5765 && col == ((space_node *)nd)->col;
5768 const char *space_node::type()
5770 return "space_node";
5773 int word_space_node::same(node *nd)
5775 return n == ((word_space_node *)nd)->n
5776 && set == ((word_space_node *)nd)->set
5777 && col == ((word_space_node *)nd)->col;
5780 const char *word_space_node::type()
5782 return "word_space_node";
5785 int word_space_node::force_tprint()
5790 int word_space_node::is_tag()
5795 void unbreakable_space_node::tprint(troff_output_file *out)
5797 out->fill_color(col);
5799 // we emit the space width as a negative glyph index
5803 out->put(-n.to_units());
5809 int unbreakable_space_node::same(node *nd)
5811 return n == ((unbreakable_space_node *)nd)->n
5812 && set == ((unbreakable_space_node *)nd)->set
5813 && col == ((unbreakable_space_node *)nd)->col;
5816 const char *unbreakable_space_node::type()
5818 return "unbreakable_space_node";
5821 node *unbreakable_space_node::add_self(node *nd, hyphen_list **p)
5824 hyphen_list *pp = *p;
5830 hyphen_list *unbreakable_space_node::get_hyphen_list(hyphen_list *tail, int *)
5832 return new hyphen_list(0, tail);
5835 int diverted_space_node::same(node *nd)
5837 return n == ((diverted_space_node *)nd)->n;
5840 const char *diverted_space_node::type()
5842 return "diverted_space_node";
5845 int diverted_space_node::force_tprint()
5850 int diverted_space_node::is_tag()
5855 int diverted_copy_file_node::same(node *nd)
5857 return filename == ((diverted_copy_file_node *)nd)->filename;
5860 const char *diverted_copy_file_node::type()
5862 return "diverted_copy_file_node";
5865 int diverted_copy_file_node::force_tprint()
5870 int diverted_copy_file_node::is_tag()
5875 // Grow the font_table so that its size is > n.
5877 static void grow_font_table(int n)
5879 assert(n >= font_table_size);
5880 font_info **old_font_table = font_table;
5881 int old_font_table_size = font_table_size;
5882 font_table_size = font_table_size ? (font_table_size*3)/2 : 10;
5883 if (font_table_size <= n)
5884 font_table_size = n + 10;
5885 font_table = new font_info *[font_table_size];
5886 if (old_font_table_size)
5887 memcpy(font_table, old_font_table,
5888 old_font_table_size*sizeof(font_info *));
5889 a_delete old_font_table;
5890 for (int i = old_font_table_size; i < font_table_size; i++)
5894 dictionary font_translation_dictionary(17);
5896 static symbol get_font_translation(symbol nm)
5898 void *p = font_translation_dictionary.lookup(nm);
5899 return p ? symbol((char *)p) : nm;
5902 dictionary font_dictionary(50);
5904 static int mount_font_no_translate(int n, symbol name, symbol external_name,
5908 // We store the address of this char in font_dictionary to indicate
5909 // that we've previously tried to mount the font and failed.
5912 void *p = font_dictionary.lookup(external_name);
5915 fm = font::load_font(external_name.contents(), ¬_found, check_only);
5920 warning(WARN_FONT, "can't find font `%1'", external_name.contents());
5921 (void)font_dictionary.lookup(external_name, &a_char);
5924 (void)font_dictionary.lookup(name, fm);
5926 else if (p == &a_char) {
5928 error("invalid font `%1'", external_name.contents());
5936 if (n >= font_table_size) {
5937 if (n - font_table_size > 1000) {
5938 error("font position too much larger than first unused position");
5943 else if (font_table[n] != 0)
5944 delete font_table[n];
5945 font_table[n] = new font_info(name, n, external_name, fm);
5946 font_family::invalidate_fontno(n);
5950 int mount_font(int n, symbol name, symbol external_name)
5953 name = get_font_translation(name);
5954 if (external_name.is_null())
5955 external_name = name;
5957 external_name = get_font_translation(external_name);
5958 return mount_font_no_translate(n, name, external_name);
5961 int check_font(symbol fam, symbol name)
5963 if (check_style(name))
5964 name = concat(fam, name);
5965 return mount_font_no_translate(0, name, name, 1);
5968 int check_style(symbol s)
5970 int i = symbol_fontno(s);
5971 return i < 0 ? 0 : font_table[i]->is_style();
5974 void mount_style(int n, symbol name)
5977 if (n >= font_table_size) {
5978 if (n - font_table_size > 1000) {
5979 error("font position too much larger than first unused position");
5984 else if (font_table[n] != 0)
5985 delete font_table[n];
5986 font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0);
5987 font_family::invalidate_fontno(n);
5990 /* global functions */
5992 void font_translate()
5994 symbol from = get_name(1);
5995 if (!from.is_null()) {
5996 symbol to = get_name();
5997 if (to.is_null() || from == to)
5998 font_translation_dictionary.remove(from);
6000 (void)font_translation_dictionary.lookup(from, (void *)to.contents());
6005 void font_position()
6008 if (get_integer(&n)) {
6010 error("negative font position");
6012 symbol internal_name = get_name(1);
6013 if (!internal_name.is_null()) {
6014 symbol external_name = get_long_name();
6015 mount_font(n, internal_name, external_name); // ignore error
6022 font_family::font_family(symbol s)
6023 : map_size(10), nm(s)
6025 map = new int[map_size];
6026 for (int i = 0; i < map_size; i++)
6030 font_family::~font_family()
6035 int font_family::make_definite(int i)
6038 if (i < map_size && map[i] >= 0)
6041 if (i < font_table_size && font_table[i] != 0) {
6042 if (i >= map_size) {
6043 int old_map_size = map_size;
6049 map = new int[map_size];
6050 memcpy(map, old_map, old_map_size*sizeof(int));
6052 for (int j = old_map_size; j < map_size; j++)
6055 if (font_table[i]->is_style()) {
6056 symbol sty = font_table[i]->get_name();
6057 symbol f = concat(nm, sty);
6059 // don't use symbol_fontno, because that might return a style
6060 // and because we don't want to translate the name
6061 for (n = 0; n < font_table_size; n++)
6062 if (font_table[n] != 0 && font_table[n]->is_named(f)
6063 && !font_table[n]->is_style())
6065 if (n >= font_table_size) {
6066 n = next_available_font_position();
6067 if (!mount_font_no_translate(n, f, f))
6083 dictionary family_dictionary(5);
6085 font_family *lookup_family(symbol nm)
6087 font_family *f = (font_family *)family_dictionary.lookup(nm);
6089 f = new font_family(nm);
6090 (void)family_dictionary.lookup(nm, f);
6095 void font_family::invalidate_fontno(int n)
6097 assert(n >= 0 && n < font_table_size);
6098 dictionary_iterator iter(family_dictionary);
6101 while (iter.get(&nam, (void **)&fam)) {
6102 int mapsize = fam->map_size;
6105 for (int i = 0; i < mapsize; i++)
6106 if (fam->map[i] == n)
6114 if (get_integer(&n)) {
6116 error("negative font position");
6118 symbol internal_name = get_name(1);
6119 if (!internal_name.is_null())
6120 mount_style(n, internal_name);
6126 static int get_fontno()
6130 if (tok.delimiter()) {
6131 symbol s = get_name(1);
6133 n = symbol_fontno(s);
6135 n = next_available_font_position();
6136 if (!mount_font(n, s))
6139 return curenv->get_family()->make_definite(n);
6142 else if (get_integer(&n)) {
6143 if (n < 0 || n >= font_table_size || font_table[n] == 0)
6144 error("bad font number");
6146 return curenv->get_family()->make_definite(n);
6151 static int underline_fontno = 2;
6153 void underline_font()
6155 int n = get_fontno();
6157 underline_fontno = n;
6161 int get_underline_fontno()
6163 return underline_fontno;
6166 void define_font_special_character()
6168 int n = get_fontno();
6173 symbol f = font_table[n]->get_name();
6174 do_define_character(CHAR_FONT_SPECIAL, f.contents());
6177 void remove_font_special_character()
6179 int n = get_fontno();
6184 symbol f = font_table[n]->get_name();
6185 while (!tok.newline() && !tok.eof()) {
6186 if (!tok.space() && !tok.tab()) {
6187 charinfo *s = tok.get_char(1);
6188 string gl(f.contents());
6190 gl += s->nm.contents();
6192 charinfo *ci = get_charinfo(symbol(gl.contents()));
6195 macro *m = ci->set_macro(0);
6204 static void read_special_fonts(special_font_list **sp)
6206 special_font_list *s = *sp;
6209 special_font_list *tem = s;
6213 special_font_list **p = sp;
6215 int i = get_fontno();
6217 special_font_list *tem = new special_font_list;
6226 void font_special_request()
6228 int n = get_fontno();
6230 read_special_fonts(&font_table[n]->sf);
6234 void special_request()
6236 read_special_fonts(&global_special_fonts);
6240 void font_zoom_request()
6242 int n = get_fontno();
6244 if (font_table[n]->is_style())
6245 warning(WARN_FONT, "can't set zoom factor for a style");
6248 if (has_arg() && get_integer(&zoom)) {
6250 warning(WARN_FONT, "can't use negative zoom factor");
6252 font_table[n]->set_zoom(zoom);
6255 font_table[n]->set_zoom(0);
6261 int next_available_font_position()
6264 for (i = 1; i < font_table_size && font_table[i] != 0; i++)
6269 int symbol_fontno(symbol s)
6271 s = get_font_translation(s);
6272 for (int i = 0; i < font_table_size; i++)
6273 if (font_table[i] != 0 && font_table[i]->is_named(s))
6278 int is_good_fontno(int n)
6280 return n >= 0 && n < font_table_size && font_table[n] != 0;
6283 int get_bold_fontno(int n)
6285 if (n >= 0 && n < font_table_size && font_table[n] != 0) {
6287 if (font_table[n]->get_bold(&offset))
6288 return offset.to_units() + 1;
6296 hunits env_digit_width(environment *env)
6298 node *n = make_glyph_node(charset_table['0'], env);
6300 hunits x = n->width();
6308 hunits env_space_width(environment *env)
6310 int fn = env_definite_font(env);
6311 font_size fs = env->get_font_size();
6312 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6313 return scale(fs.to_units()/3, env->get_space_size(), 12);
6315 return font_table[fn]->get_space_width(fs, env->get_space_size());
6318 hunits env_sentence_space_width(environment *env)
6320 int fn = env_definite_font(env);
6321 font_size fs = env->get_font_size();
6322 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6323 return scale(fs.to_units()/3, env->get_sentence_space_size(), 12);
6325 return font_table[fn]->get_space_width(fs, env->get_sentence_space_size());
6328 hunits env_half_narrow_space_width(environment *env)
6330 int fn = env_definite_font(env);
6331 font_size fs = env->get_font_size();
6332 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6335 return font_table[fn]->get_half_narrow_space_width(fs);
6338 hunits env_narrow_space_width(environment *env)
6340 int fn = env_definite_font(env);
6341 font_size fs = env->get_font_size();
6342 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6345 return font_table[fn]->get_narrow_space_width(fs);
6350 int n = get_fontno();
6353 if (tok.delimiter()) {
6354 int f = get_fontno();
6357 if (has_arg() && get_number(&offset, 'u') && offset >= 1)
6358 font_table[f]->set_conditional_bold(n, hunits(offset - 1));
6360 font_table[f]->conditional_unbold(n);
6365 if (get_number(&offset, 'u') && offset >= 1)
6366 font_table[n]->set_bold(hunits(offset - 1));
6368 font_table[n]->unbold();
6372 font_table[n]->unbold();
6377 track_kerning_function::track_kerning_function() : non_zero(0)
6381 track_kerning_function::track_kerning_function(int min_s, hunits min_a,
6382 int max_s, hunits max_a)
6383 : non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s),
6388 int track_kerning_function::operator==(const track_kerning_function &tk)
6392 && min_size == tk.min_size
6393 && min_amount == tk.min_amount
6394 && max_size == tk.max_size
6395 && max_amount == tk.max_amount);
6397 return !tk.non_zero;
6400 int track_kerning_function::operator!=(const track_kerning_function &tk)
6403 return (!tk.non_zero
6404 || min_size != tk.min_size
6405 || min_amount != tk.min_amount
6406 || max_size != tk.max_size
6407 || max_amount != tk.max_amount);
6412 hunits track_kerning_function::compute(int size)
6415 if (max_size <= min_size)
6417 else if (size <= min_size)
6419 else if (size >= max_size)
6422 return (scale(max_amount, size - min_size, max_size - min_size)
6423 + scale(min_amount, max_size - size, max_size - min_size));
6431 int n = get_fontno();
6434 hunits min_a, max_a;
6436 && get_number(&min_s, 'z')
6437 && get_hunits(&min_a, 'p')
6438 && get_number(&max_s, 'z')
6439 && get_hunits(&max_a, 'p')) {
6440 track_kerning_function tk(min_s, min_a, max_s, max_a);
6441 font_table[n]->set_track_kern(tk);
6444 track_kerning_function tk;
6445 font_table[n]->set_track_kern(tk);
6451 void constant_space()
6453 int n = get_fontno();
6456 if (!has_arg() || !get_integer(&x))
6457 font_table[n]->set_constant_space(CONSTANT_SPACE_NONE);
6459 if (!has_arg() || !get_number(&y, 'z'))
6460 font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x);
6462 font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE,
6474 if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2)
6475 global_ligature_mode = lig;
6477 global_ligature_mode = 1;
6484 if (has_arg() && get_integer(&k))
6485 global_kern_mode = k != 0;
6487 global_kern_mode = 1;
6491 void set_soft_hyphen_char()
6493 soft_hyphen_char = get_optional_char();
6494 if (!soft_hyphen_char)
6495 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
6501 if (suppress_output_flag)
6502 the_output = new suppress_output_file;
6503 else if (ascii_output_flag)
6504 the_output = new ascii_output_file;
6506 the_output = new troff_output_file;
6509 class next_available_font_position_reg : public reg {
6511 const char *get_string();
6514 const char *next_available_font_position_reg::get_string()
6516 return i_to_a(next_available_font_position());
6519 class printing_reg : public reg {
6521 const char *get_string();
6524 const char *printing_reg::get_string()
6527 return the_output->is_printing() ? "1" : "0";
6532 void init_node_requests()
6534 init_request("bd", bold_font);
6535 init_request("cs", constant_space);
6536 init_request("fp", font_position);
6537 init_request("fschar", define_font_special_character);
6538 init_request("fspecial", font_special_request);
6539 init_request("fzoom", font_zoom_request);
6540 init_request("ftr", font_translate);
6541 init_request("kern", kern_request);
6542 init_request("lg", ligature);
6543 init_request("rfschar", remove_font_special_character);
6544 init_request("shc", set_soft_hyphen_char);
6545 init_request("special", special_request);
6546 init_request("sty", style);
6547 init_request("tkf", track_kern);
6548 init_request("uf", underline_font);
6549 number_reg_dictionary.define(".fp", new next_available_font_position_reg);
6550 number_reg_dictionary.define(".kern",
6551 new constant_int_reg(&global_kern_mode));
6552 number_reg_dictionary.define(".lg",
6553 new constant_int_reg(&global_ligature_mode));
6554 number_reg_dictionary.define(".P", new printing_reg);
6555 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);