2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
29 #include "dictionary.h"
48 #else /* not _POSIX_VERSION */
50 /* traditional Unix */
52 #define WIFEXITED(s) (((s) & 0377) == 0)
53 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
54 #define WTERMSIG(s) ((s) & 0177)
55 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
56 #define WSTOPSIG(s) (((s) >> 8) & 0377)
57 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
59 #endif /* not _POSIX_VERSION */
62 * how many boundaries of images have been written? Useful for
67 static int suppress_start_page = 0;
71 symbol HYPHEN_SYMBOL("hy");
73 // Character used when a hyphen is inserted at a line break.
74 static charinfo *soft_hyphen_char;
76 enum constant_space_type {
78 CONSTANT_SPACE_RELATIVE,
79 CONSTANT_SPACE_ABSOLUTE
82 struct special_font_list {
84 special_font_list *next;
87 special_font_list *global_special_fonts;
88 static int global_ligature_mode = 1;
89 static int global_kern_mode = 1;
91 class track_kerning_function {
98 track_kerning_function();
99 track_kerning_function(units, hunits, units, hunits);
100 int operator==(const track_kerning_function &);
101 int operator!=(const track_kerning_function &);
102 hunits compute(int point_size);
105 // embolden fontno when this is the current font
107 struct conditional_bold {
108 conditional_bold *next;
111 conditional_bold(int, hunits, conditional_bold * = 0);
122 symbol internal_name;
123 symbol external_name;
127 track_kerning_function track_kern;
128 constant_space_type is_constant_spaced;
129 units constant_space;
130 int last_ligature_mode;
132 conditional_bold *cond_bold_list;
135 special_font_list *sf;
136 font_info(symbol nm, int n, symbol enm, font *f);
137 int contains(charinfo *);
138 void set_bold(hunits);
140 void set_conditional_bold(int, hunits);
141 void conditional_unbold(int);
142 void set_track_kern(track_kerning_function &);
143 void set_constant_space(constant_space_type, units = 0);
144 int is_named(symbol);
146 tfont *get_tfont(font_size, int, int, int);
147 hunits get_space_width(font_size, int);
148 hunits get_narrow_space_width(font_size);
149 hunits get_half_narrow_space_width(font_size);
150 int get_bold(hunits *);
153 friend symbol get_font_name(int, environment *);
163 char is_constant_spaced;
167 hunits track_kern; // add this to the width
168 hunits constant_space_width;
172 tfont_spec(symbol nm, int pos, font *, font_size, int, int);
173 tfont_spec(const tfont_spec &spec) { *this = spec; }
175 int operator==(const tfont_spec &);
176 friend tfont *font_info::get_tfont(font_size fs, int, int, int);
179 class tfont : public tfont_spec {
180 static tfont *tfont_list;
182 tfont *plain_version;
185 int contains(charinfo *);
186 hunits get_width(charinfo *c);
187 int get_bold(hunits *);
188 int get_constant_space(hunits *);
189 hunits get_track_kern();
191 font_size get_size();
193 charinfo *get_lig(charinfo *c1, charinfo *c2);
194 int get_kern(charinfo *c1, charinfo *c2, hunits *res);
195 int get_input_position();
196 int get_character_type(charinfo *);
199 vunits get_char_height(charinfo *);
200 vunits get_char_depth(charinfo *);
201 hunits get_char_skew(charinfo *);
202 hunits get_italic_correction(charinfo *);
203 hunits get_left_italic_correction(charinfo *);
204 hunits get_subscript_correction(charinfo *);
205 friend tfont *make_tfont(tfont_spec &);
208 inline int env_definite_font(environment *env)
210 return env->get_family()->make_definite(env->get_font());
213 /* font_info functions */
215 static font_info **font_table = 0;
216 static int font_table_size = 0;
218 font_info::font_info(symbol nm, int n, symbol enm, font *f)
219 : last_tfont(0), number(n), last_size(0),
220 internal_name(nm), external_name(enm), fm(f),
221 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1),
222 last_kern_mode(1), cond_bold_list(0), sf(0)
226 inline int font_info::contains(charinfo *ci)
228 return fm != 0 && fm->contains(ci->get_index());
231 inline int font_info::is_special()
233 return fm != 0 && fm->is_special();
236 inline int font_info::is_style()
241 tfont *make_tfont(tfont_spec &spec)
243 for (tfont *p = tfont::tfont_list; p; p = p->next)
246 return new tfont(spec);
249 // this is the current_font, fontno is where we found the character,
250 // presumably a special font
252 tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
254 if (last_tfont == 0 || fs != last_size
255 || height != last_height || slant != last_slant
256 || global_ligature_mode != last_ligature_mode
257 || global_kern_mode != last_kern_mode
258 || fontno != number) {
259 font_info *f = font_table[fontno];
260 tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
261 for (conditional_bold *p = cond_bold_list; p; p = p->next)
262 if (p->fontno == fontno) {
264 spec.bold_offset = p->offset;
267 if (!spec.is_bold && is_bold) {
269 spec.bold_offset = bold_offset;
271 spec.track_kern = track_kern.compute(fs.to_scaled_points());
272 spec.ligature_mode = global_ligature_mode;
273 spec.kern_mode = global_kern_mode;
274 switch (is_constant_spaced) {
275 case CONSTANT_SPACE_NONE:
277 case CONSTANT_SPACE_ABSOLUTE:
278 spec.is_constant_spaced = 1;
279 spec.constant_space_width = constant_space;
281 case CONSTANT_SPACE_RELATIVE:
282 spec.is_constant_spaced = 1;
283 spec.constant_space_width
284 = scale(constant_space*fs.to_scaled_points(),
291 if (fontno != number)
292 return make_tfont(spec);
293 last_tfont = make_tfont(spec);
295 last_height = height;
297 last_ligature_mode = global_ligature_mode;
298 last_kern_mode = global_kern_mode;
303 int font_info::get_bold(hunits *res)
313 void font_info::unbold()
321 void font_info::set_bold(hunits offset)
323 if (!is_bold || offset != bold_offset) {
325 bold_offset = offset;
330 void font_info::set_conditional_bold(int fontno, hunits offset)
332 for (conditional_bold *p = cond_bold_list; p; p = p->next)
333 if (p->fontno == fontno) {
334 if (offset != p->offset) {
340 cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
343 conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
344 : next(x), fontno(f), offset(h)
348 void font_info::conditional_unbold(int fontno)
350 for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
351 if ((*p)->fontno == fontno) {
352 conditional_bold *tem = *p;
360 void font_info::set_constant_space(constant_space_type type, units x)
362 if (type != is_constant_spaced
363 || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
365 is_constant_spaced = type;
370 void font_info::set_track_kern(track_kerning_function &tk)
372 if (track_kern != tk) {
378 void font_info::flush()
383 int font_info::is_named(symbol s)
385 return internal_name == s;
388 symbol font_info::get_name()
390 return internal_name;
393 symbol get_font_name(int fontno, environment *env)
395 symbol f = font_table[fontno]->get_name();
396 if (font_table[fontno]->is_style()) {
397 return concat(env->get_family()->nm, f);
402 hunits font_info::get_space_width(font_size fs, int space_size)
404 if (is_constant_spaced == CONSTANT_SPACE_NONE)
405 return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
407 else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
408 return constant_space;
410 return scale(constant_space*fs.to_scaled_points(),
411 units_per_inch, 36*72*sizescale);
414 hunits font_info::get_narrow_space_width(font_size fs)
416 charinfo *ci = get_charinfo(symbol("|"));
417 if (fm->contains(ci->get_index()))
418 return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
420 return hunits(fs.to_units()/6);
423 hunits font_info::get_half_narrow_space_width(font_size fs)
425 charinfo *ci = get_charinfo(symbol("^"));
426 if (fm->contains(ci->get_index()))
427 return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
429 return hunits(fs.to_units()/12);
434 tfont_spec::tfont_spec(symbol nm, int n, font *f,
435 font_size s, int h, int sl)
436 : name(nm), input_position(n), fm(f), size(s),
437 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
440 if (height == size.to_scaled_points())
444 int tfont_spec::operator==(const tfont_spec &spec)
448 && input_position == spec.input_position
450 && height == spec.height
451 && slant == spec.slant
453 ? (spec.is_bold && bold_offset == spec.bold_offset)
455 && track_kern == spec.track_kern
456 && (is_constant_spaced
457 ? (spec.is_constant_spaced
458 && constant_space_width == spec.constant_space_width)
459 : !spec.is_constant_spaced)
460 && ligature_mode == spec.ligature_mode
461 && kern_mode == spec.kern_mode)
467 tfont_spec tfont_spec::plain()
469 return tfont_spec(name, input_position, fm, size, height, slant);
472 hunits tfont::get_width(charinfo *c)
474 if (is_constant_spaced)
475 return constant_space_width;
477 return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
478 + track_kern + bold_offset);
480 return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
484 vunits tfont::get_char_height(charinfo *c)
486 vunits v = fm->get_height(c->get_index(), size.to_scaled_points());
487 if (height != 0 && height != size.to_scaled_points())
488 return scale(v, height, size.to_scaled_points());
493 vunits tfont::get_char_depth(charinfo *c)
495 vunits v = fm->get_depth(c->get_index(), size.to_scaled_points());
496 if (height != 0 && height != size.to_scaled_points())
497 return scale(v, height, size.to_scaled_points());
502 hunits tfont::get_char_skew(charinfo *c)
504 return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant));
507 hunits tfont::get_italic_correction(charinfo *c)
509 return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points()));
512 hunits tfont::get_left_italic_correction(charinfo *c)
514 return hunits(fm->get_left_italic_correction(c->get_index(),
515 size.to_scaled_points()));
518 hunits tfont::get_subscript_correction(charinfo *c)
520 return hunits(fm->get_subscript_correction(c->get_index(),
521 size.to_scaled_points()));
524 inline int tfont::get_input_position()
526 return input_position;
529 inline int tfont::contains(charinfo *ci)
531 return fm->contains(ci->get_index());
534 inline int tfont::get_character_type(charinfo *ci)
536 return fm->get_character_type(ci->get_index());
539 inline int tfont::get_bold(hunits *res)
549 inline int tfont::get_constant_space(hunits *res)
551 if (is_constant_spaced) {
552 *res = constant_space_width;
559 inline hunits tfont::get_track_kern()
564 inline tfont *tfont::get_plain()
566 return plain_version;
569 inline font_size tfont::get_size()
574 inline symbol tfont::get_name()
579 inline int tfont::get_height()
584 inline int tfont::get_slant()
589 symbol SYMBOL_ff("ff");
590 symbol SYMBOL_fi("fi");
591 symbol SYMBOL_fl("fl");
592 symbol SYMBOL_Fi("Fi");
593 symbol SYMBOL_Fl("Fl");
595 charinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
597 if (ligature_mode == 0)
600 if (c1->get_ascii_code() == 'f') {
601 switch (c2->get_ascii_code()) {
603 if (fm->has_ligature(font::LIG_ff))
604 ci = get_charinfo(SYMBOL_ff);
607 if (fm->has_ligature(font::LIG_fi))
608 ci = get_charinfo(SYMBOL_fi);
611 if (fm->has_ligature(font::LIG_fl))
612 ci = get_charinfo(SYMBOL_fl);
616 else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
617 switch (c2->get_ascii_code()) {
619 if (fm->has_ligature(font::LIG_ffi))
620 ci = get_charinfo(SYMBOL_Fi);
623 if (fm->has_ligature(font::LIG_ffl))
624 ci = get_charinfo(SYMBOL_Fl);
628 if (ci != 0 && fm->contains(ci->get_index()))
633 inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
638 int n = fm->get_kern(c1->get_index(),
640 size.to_scaled_points());
650 tfont *tfont::tfont_list = 0;
652 tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
656 tfont_spec plain_spec = plain();
658 for (p = tfont_list; p; p = p->next)
659 if (*p == plain_spec) {
664 plain_version = new tfont(plain_spec);
669 class real_output_file : public output_file {
670 #ifndef POPEN_MISSING
673 int printing; // decision via optional page list
674 int output_on; // \O[0] or \O[1] escape calls
675 virtual void really_transparent_char(unsigned char) = 0;
676 virtual void really_print_line(hunits x, vunits y, node *n,
677 vunits before, vunits after, hunits width) = 0;
678 virtual void really_begin_page(int pageno, vunits page_length) = 0;
679 virtual void really_copy_file(hunits x, vunits y, const char *filename);
680 virtual void really_put_filename(const char *filename);
681 virtual void really_on();
682 virtual void really_off();
689 void transparent_char(unsigned char);
690 void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
691 void begin_page(int pageno, vunits page_length);
692 void put_filename(const char *filename);
697 void copy_file(hunits x, vunits y, const char *filename);
700 class suppress_output_file : public real_output_file {
702 suppress_output_file();
703 void really_transparent_char(unsigned char);
704 void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
705 void really_begin_page(int pageno, vunits page_length);
708 class ascii_output_file : public real_output_file {
711 void really_transparent_char(unsigned char);
712 void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
713 void really_begin_page(int pageno, vunits page_length);
714 void outc(unsigned char c);
715 void outs(const char *s);
718 void ascii_output_file::outc(unsigned char c)
723 void ascii_output_file::outs(const char *s)
733 class troff_output_file : public real_output_file {
742 tfont *current_tfont;
743 color *current_fill_color;
744 color *current_glyph_color;
745 int current_font_number;
746 symbol *font_position;
748 enum { TBUF_SIZE = 256 };
749 char tbuf[TBUF_SIZE];
755 void put(unsigned char c);
757 void put(unsigned int i);
758 void put(const char *s);
759 void set_font(tfont *tf);
763 ~troff_output_file();
764 void trailer(vunits page_length);
765 void put_char(charinfo *, tfont *, color *, color *);
766 void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits);
769 void moveto(hunits, vunits);
770 void start_special(tfont *, color *, color *, int = 0);
771 void start_special();
772 void special_char(unsigned char c);
775 void really_transparent_char(unsigned char c);
776 void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
777 void really_begin_page(int pageno, vunits page_length);
778 void really_copy_file(hunits x, vunits y, const char *filename);
779 void really_put_filename(const char *filename);
782 void draw(char, hvpair *, int, font_size, color *, color *);
783 void determine_line_limits (char code, hvpair *point, int npoints);
784 void check_charinfo(tfont *tf, charinfo *ci);
785 void glyph_color(color *c);
786 void fill_color(color *c);
787 int get_hpos() { return hpos; }
788 int get_vpos() { return vpos; }
791 static void put_string(const char *s, FILE *fp)
793 for (; *s != '\0'; ++s)
797 inline void troff_output_file::put(char c)
802 inline void troff_output_file::put(unsigned char c)
807 inline void troff_output_file::put(const char *s)
812 inline void troff_output_file::put(int i)
814 put_string(i_to_a(i), fp);
817 inline void troff_output_file::put(unsigned int i)
819 put_string(ui_to_a(i), fp);
822 void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol,
827 if (tf != current_tfont)
835 void troff_output_file::start_special()
842 void troff_output_file::special_char(unsigned char c)
849 void troff_output_file::end_special()
854 inline void troff_output_file::moveto(hunits h, vunits v)
860 void troff_output_file::really_print_line(hunits x, vunits y, node *n,
861 vunits before, vunits after, hunits width)
869 // This ensures that transparent throughput will have a more predictable
875 put(before.to_units());
877 put(after.to_units());
881 inline void troff_output_file::word_marker()
888 inline void troff_output_file::right(hunits n)
890 hpos += n.to_units();
893 inline void troff_output_file::down(vunits n)
895 vpos += n.to_units();
898 void troff_output_file::do_motion()
909 if (hpos != output_hpos) {
910 units n = hpos - output_hpos;
911 if (n > 0 && n < hpos) {
921 if (vpos != output_vpos) {
922 units n = vpos - output_vpos;
923 if (n > 0 && n < vpos) {
939 void troff_output_file::flush_tbuf()
955 check_output_limits(hpos, vpos);
956 check_output_limits(hpos, vpos - current_size);
958 for (int i = 0; i < tbuf_len; i++)
964 void troff_output_file::check_charinfo(tfont *tf, charinfo *ci)
969 int height = tf->get_char_height(ci).to_units();
970 int width = tf->get_width(ci).to_units()
971 + tf->get_italic_correction(ci).to_units();
972 int depth = tf->get_char_depth(ci).to_units();
973 check_output_limits(output_hpos, output_vpos - height);
974 check_output_limits(output_hpos + width, output_vpos + depth);
977 void troff_output_file::put_char_width(charinfo *ci, tfont *tf,
978 color *gcol, color *fcol,
981 int kk = k.to_units();
984 hpos += w.to_units() + kk;
987 if (tf != current_tfont) {
991 char c = ci->get_ascii_code();
997 check_charinfo(tf, ci);
998 if (ci->numbered()) {
1000 put(ci->get_number());
1004 const char *s = ci->nm.contents();
1013 hpos += w.to_units() + kk;
1015 else if (tcommand_flag) {
1016 if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
1017 && (!gcol || gcol == current_glyph_color)
1018 && (!fcol || fcol == current_fill_color)
1020 && tbuf_len < TBUF_SIZE) {
1021 check_charinfo(tf, ci);
1022 tbuf[tbuf_len++] = c;
1023 output_hpos += w.to_units() + kk;
1031 check_charinfo(tf, ci);
1032 tbuf[tbuf_len++] = c;
1033 output_hpos += w.to_units() + kk;
1039 int n = hpos - output_hpos;
1040 check_charinfo(tf, ci);
1041 // check_output_limits(output_hpos, output_vpos);
1042 if (vpos == output_vpos
1043 && (!gcol || gcol == current_glyph_color)
1044 && (!fcol || fcol == current_fill_color)
1045 && n > 0 && n < 100 && !force_motion) {
1046 put(char(n/10 + '0'));
1047 put(char(n%10 + '0'));
1056 hpos += w.to_units() + kk;
1060 void troff_output_file::put_char(charinfo *ci, tfont *tf,
1061 color *gcol, color *fcol)
1066 if (tf != current_tfont)
1068 char c = ci->get_ascii_code();
1073 if (ci->numbered()) {
1075 put(ci->get_number());
1079 const char *s = ci->nm.contents();
1090 int n = hpos - output_hpos;
1091 if (vpos == output_vpos
1092 && (!gcol || gcol == current_glyph_color)
1093 && (!fcol || fcol == current_fill_color)
1094 && n > 0 && n < 100) {
1095 put(char(n/10 + '0'));
1096 put(char(n%10 + '0'));
1110 void troff_output_file::set_font(tfont *tf)
1112 if (current_tfont == tf)
1114 int n = tf->get_input_position();
1115 symbol nm = tf->get_name();
1116 if (n >= nfont_positions || font_position[n] != nm) {
1122 if (n >= nfont_positions) {
1123 int old_nfont_positions = nfont_positions;
1124 symbol *old_font_position = font_position;
1125 nfont_positions *= 3;
1126 nfont_positions /= 2;
1127 if (nfont_positions <= n)
1128 nfont_positions = n + 10;
1129 font_position = new symbol[nfont_positions];
1130 memcpy(font_position, old_font_position,
1131 old_nfont_positions*sizeof(symbol));
1132 a_delete old_font_position;
1134 font_position[n] = nm;
1136 if (current_font_number != n) {
1140 current_font_number = n;
1142 int size = tf->get_size().to_scaled_points();
1143 if (current_size != size) {
1147 current_size = size;
1149 int slant = tf->get_slant();
1150 if (current_slant != slant) {
1154 current_slant = slant;
1156 int height = tf->get_height();
1157 if (current_height != height) {
1159 put(height == 0 ? current_size : height);
1161 current_height = height;
1166 void troff_output_file::fill_color(color *col)
1168 if (!col || current_fill_color == col || !color_flag)
1172 unsigned int components[4];
1174 cs = col->get_components(components);
1211 current_fill_color = col;
1214 void troff_output_file::glyph_color(color *col)
1216 if (!col || current_glyph_color == col || !color_flag)
1220 unsigned int components[4];
1222 cs = col->get_components(components);
1259 current_glyph_color = col;
1262 // determine_line_limits - works out the smallest box which will contain
1263 // the entity, code, built from the point array.
1264 void troff_output_file::determine_line_limits(char code, hvpair *point,
1275 // only the h field is used when defining a circle
1276 check_output_limits(output_hpos,
1277 output_vpos - point[0].h.to_units()/2);
1278 check_output_limits(output_hpos + point[0].h.to_units(),
1279 output_vpos + point[0].h.to_units()/2);
1283 check_output_limits(output_hpos,
1284 output_vpos - point[0].v.to_units()/2);
1285 check_output_limits(output_hpos + point[0].h.to_units(),
1286 output_vpos + point[0].v.to_units()/2);
1292 check_output_limits(x, y);
1293 for (i = 0; i < npoints; i++) {
1294 x += point[i].h.to_units();
1295 y += point[i].v.to_units();
1296 check_output_limits(x, y);
1302 for (i = 0; i < npoints; i++) {
1303 x += point[i].h.to_units();
1304 y += point[i].v.to_units();
1305 check_output_limits(x, y);
1311 int minx, miny, maxx, maxy;
1314 p[0] = point[0].h.to_units();
1315 p[1] = point[0].v.to_units();
1316 p[2] = point[1].h.to_units();
1317 p[3] = point[1].v.to_units();
1318 if (adjust_arc_center(p, c)) {
1319 check_output_arc_limits(x, y,
1320 p[0], p[1], p[2], p[3],
1322 &minx, &maxx, &miny, &maxy);
1323 check_output_limits(minx, miny);
1324 check_output_limits(maxx, maxy);
1331 check_output_limits(x, y);
1332 for (i = 0; i < npoints; i++) {
1333 x += point[i].h.to_units();
1334 y += point[i].v.to_units();
1335 check_output_limits(x, y);
1341 for (i = 0; i < npoints; i++) {
1342 x += point[i].h.to_units();
1343 y += point[i].v.to_units();
1344 check_output_limits(x, y);
1349 void troff_output_file::draw(char code, hvpair *point, int npoints,
1350 font_size fsize, color *gcol, color *fcol)
1358 int size = fsize.to_scaled_points();
1359 if (current_size != size) {
1363 current_size = size;
1370 put(point[0].h.to_units());
1373 for (i = 0; i < npoints; i++) {
1375 put(point[i].h.to_units());
1377 put(point[i].v.to_units());
1379 determine_line_limits(code, point, npoints);
1382 for (i = 0; i < npoints; i++)
1383 output_hpos += point[i].h.to_units();
1386 for (i = 0; i < npoints; i++)
1387 output_vpos += point[i].v.to_units();
1394 void troff_output_file::really_on()
1401 void troff_output_file::really_off()
1406 void troff_output_file::really_put_filename(const char *filename)
1414 void troff_output_file::really_begin_page(int pageno, vunits page_length)
1418 if (page_length > V0) {
1420 put(page_length.to_units());
1427 current_font_number = -1;
1429 // current_height = 0;
1430 // current_slant = 0;
1436 for (int i = 0; i < nfont_positions; i++)
1437 font_position[i] = NULL_SYMBOL;
1443 void troff_output_file::really_copy_file(hunits x, vunits y, const char *filename)
1449 FILE *ifp = fopen(filename, "r");
1451 error("can't open `%1': %2", filename, strerror(errno));
1454 while ((c = getc(ifp)) != EOF)
1461 current_font_number = -1;
1462 for (int i = 0; i < nfont_positions; i++)
1463 font_position[i] = NULL_SYMBOL;
1466 void troff_output_file::really_transparent_char(unsigned char c)
1471 troff_output_file::~troff_output_file()
1473 a_delete font_position;
1476 void troff_output_file::trailer(vunits page_length)
1479 if (page_length > V0) {
1482 put(page_length.to_units());
1488 troff_output_file::troff_output_file()
1489 : current_slant(0), current_height(0), nfont_positions(10), tbuf_len(0),
1492 font_position = new symbol[nfont_positions];
1497 put(units_per_inch);
1508 output_file *the_output = 0;
1510 output_file::output_file()
1514 output_file::~output_file()
1518 void output_file::trailer(vunits)
1522 void output_file::put_filename(const char *filename)
1526 void output_file::on()
1530 void output_file::off()
1534 real_output_file::real_output_file()
1535 : printing(0), output_on(1)
1537 #ifndef POPEN_MISSING
1539 if ((fp = popen(pipe_command, POPEN_WT)) != 0) {
1543 error("pipe open failed: %1", strerror(errno));
1546 #endif /* not POPEN_MISSING */
1550 real_output_file::~real_output_file()
1554 // To avoid looping, set fp to 0 before calling fatal().
1555 if (ferror(fp) || fflush(fp) < 0) {
1557 fatal("error writing output file");
1559 #ifndef POPEN_MISSING
1561 int result = pclose(fp);
1564 fatal("pclose failed");
1565 if (!WIFEXITED(result))
1566 error("output process `%1' got fatal signal %2",
1568 WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result));
1570 int exit_status = WEXITSTATUS(result);
1571 if (exit_status != 0)
1572 error("output process `%1' exited with status %2",
1573 pipe_command, exit_status);
1577 #endif /* not POPEN MISSING */
1578 if (fclose(fp) < 0) {
1580 fatal("error closing output file");
1584 void real_output_file::flush()
1587 fatal("error writing output file");
1590 int real_output_file::is_printing()
1595 void real_output_file::begin_page(int pageno, vunits page_length)
1597 printing = in_output_page_list(pageno);
1599 really_begin_page(pageno, page_length);
1602 void real_output_file::copy_file(hunits x, vunits y, const char *filename)
1604 if (printing && output_on)
1605 really_copy_file(x, y, filename);
1606 check_output_limits(x.to_units(), y.to_units());
1609 void real_output_file::transparent_char(unsigned char c)
1611 if (printing && output_on)
1612 really_transparent_char(c);
1615 void real_output_file::print_line(hunits x, vunits y, node *n,
1616 vunits before, vunits after, hunits width)
1619 really_print_line(x, y, n, before, after, width);
1620 delete_node_list(n);
1623 void real_output_file::really_copy_file(hunits, vunits, const char *)
1628 void real_output_file::put_filename(const char *filename)
1630 really_put_filename(filename);
1633 void real_output_file::really_put_filename(const char *filename)
1637 void real_output_file::on()
1644 void real_output_file::off()
1650 int real_output_file::is_on()
1655 void real_output_file::really_on()
1659 void real_output_file::really_off()
1663 /* ascii_output_file */
1665 void ascii_output_file::really_transparent_char(unsigned char c)
1670 void ascii_output_file::really_print_line(hunits, vunits, node *n, vunits, vunits, hunits width)
1673 n->ascii_print(this);
1679 void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
1681 fputs("<beginning of page>\n", fp);
1684 ascii_output_file::ascii_output_file()
1688 /* suppress_output_file */
1690 suppress_output_file::suppress_output_file()
1694 void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits)
1698 void suppress_output_file::really_begin_page(int, vunits)
1702 void suppress_output_file::really_transparent_char(unsigned char)
1706 /* glyphs, ligatures, kerns, discretionary breaks */
1708 class charinfo_node : public node {
1712 charinfo_node(charinfo *, node * = 0);
1713 int ends_sentence();
1714 int overlaps_vertically();
1715 int overlaps_horizontally();
1718 charinfo_node::charinfo_node(charinfo *c, node *x)
1723 int charinfo_node::ends_sentence()
1725 if (ci->ends_sentence())
1727 else if (ci->transparent())
1733 int charinfo_node::overlaps_horizontally()
1735 return ci->overlaps_horizontally();
1738 int charinfo_node::overlaps_vertically()
1740 return ci->overlaps_vertically();
1743 class glyph_node : public charinfo_node {
1744 static glyph_node *free_list;
1748 color *fcol; /* this is needed for grotty */
1751 glyph_node(charinfo *, tfont *, color *, color *, hunits, node * = 0);
1754 void *operator new(size_t);
1755 void operator delete(void *);
1756 glyph_node(charinfo *, tfont *, color *, color *, node * = 0);
1759 node *merge_glyph_node(glyph_node *);
1760 node *merge_self(node *);
1762 node *last_char_node();
1764 void vertical_extent(vunits *, vunits *);
1765 hunits subscript_correction();
1766 hunits italic_correction();
1767 hunits left_italic_correction();
1769 hyphenation_type get_hyphenation_type();
1771 color *get_glyph_color();
1772 color *get_fill_color();
1773 void tprint(troff_output_file *);
1774 void zero_width_tprint(troff_output_file *);
1775 hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
1776 node *add_self(node *, hyphen_list **);
1777 void ascii_print(ascii_output_file *);
1778 void asciify(macro *);
1779 int character_type();
1785 glyph_node *glyph_node::free_list = 0;
1787 class ligature_node : public glyph_node {
1791 ligature_node(charinfo *, tfont *, color *, color *, hunits,
1792 node *, node *, node * = 0);
1795 void *operator new(size_t);
1796 void operator delete(void *);
1797 ligature_node(charinfo *, tfont *, color *, color *,
1798 node *, node *, node * = 0);
1801 node *add_self(node *, hyphen_list **);
1802 hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
1803 void ascii_print(ascii_output_file *);
1804 void asciify(macro *);
1810 class kern_pair_node : public node {
1815 kern_pair_node(hunits n, node *first, node *second, node *x = 0);
1818 node *merge_glyph_node(glyph_node *);
1819 node *add_self(node *, hyphen_list **);
1820 hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
1821 node *add_discretionary_hyphen();
1823 node *last_char_node();
1824 hunits italic_correction();
1825 hunits subscript_correction();
1826 void tprint(troff_output_file *);
1827 hyphenation_type get_hyphenation_type();
1828 int ends_sentence();
1829 void ascii_print(ascii_output_file *);
1830 void asciify(macro *);
1834 void vertical_extent(vunits *, vunits *);
1837 class dbreak_node : public node {
1842 dbreak_node(node *n, node *p, node *x = 0);
1845 node *merge_glyph_node(glyph_node *);
1846 node *add_discretionary_hyphen();
1848 node *last_char_node();
1849 hunits italic_correction();
1850 hunits subscript_correction();
1851 void tprint(troff_output_file *);
1852 breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
1855 int ends_sentence();
1856 void split(int, node **, node **);
1857 hyphenation_type get_hyphenation_type();
1858 void ascii_print(ascii_output_file *);
1859 void asciify(macro *);
1865 void *glyph_node::operator new(size_t n)
1867 assert(n == sizeof(glyph_node));
1869 const int BLOCK = 1024;
1870 free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
1871 for (int i = 0; i < BLOCK - 1; i++)
1872 free_list[i].next = free_list + i + 1;
1873 free_list[BLOCK-1].next = 0;
1875 glyph_node *p = free_list;
1876 free_list = (glyph_node *)(free_list->next);
1881 void *ligature_node::operator new(size_t n)
1886 void glyph_node::operator delete(void *p)
1889 ((glyph_node *)p)->next = free_list;
1890 free_list = (glyph_node *)p;
1894 void ligature_node::operator delete(void *p)
1899 glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc, node *x)
1900 : charinfo_node(c, x), tf(t), gcol(gc), fcol(fc)
1903 wid = tf->get_width(ci);
1908 glyph_node::glyph_node(charinfo *c, tfont *t,
1909 color *gc, color *fc, hunits w, node *x)
1910 : charinfo_node(c, x), tf(t), gcol(gc), fcol(fc), wid(w)
1915 node *glyph_node::copy()
1918 return new glyph_node(ci, tf, gcol, fcol, wid);
1920 return new glyph_node(ci, tf, gcol, fcol);
1924 node *glyph_node::merge_self(node *nd)
1926 return nd->merge_glyph_node(this);
1929 int glyph_node::character_type()
1931 return tf->get_character_type(ci);
1934 node *glyph_node::add_self(node *n, hyphen_list **p)
1936 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
1939 if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
1944 nn = nn->add_discretionary_hyphen();
1945 hyphen_list *pp = *p;
1951 units glyph_node::size()
1953 return tf->get_size().to_units();
1956 hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail)
1958 return new hyphen_list(ci->get_hyphenation_code(), tail);
1961 tfont *node::get_tfont()
1966 tfont *glyph_node::get_tfont()
1971 color *node::get_glyph_color()
1976 color *glyph_node::get_glyph_color()
1981 color *node::get_fill_color()
1986 color *glyph_node::get_fill_color()
1991 node *node::merge_glyph_node(glyph_node * /*gn*/)
1996 node *glyph_node::merge_glyph_node(glyph_node *gn)
1998 if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) {
2000 if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
2003 return new ligature_node(lig, tf, gcol, fcol, this, gn, next1);
2006 if (tf->get_kern(ci, gn->ci, &kern)) {
2009 return new kern_pair_node(kern, this, gn, next1);
2018 hunits glyph_node::width()
2023 return tf->get_width(ci);
2027 node *glyph_node::last_char_node()
2032 void glyph_node::vertical_extent(vunits *min, vunits *max)
2034 *min = -tf->get_char_height(ci);
2035 *max = tf->get_char_depth(ci);
2038 hunits glyph_node::skew()
2040 return tf->get_char_skew(ci);
2043 hunits glyph_node::subscript_correction()
2045 return tf->get_subscript_correction(ci);
2048 hunits glyph_node::italic_correction()
2050 return tf->get_italic_correction(ci);
2053 hunits glyph_node::left_italic_correction()
2055 return tf->get_left_italic_correction(ci);
2058 hyphenation_type glyph_node::get_hyphenation_type()
2060 return HYPHEN_MIDDLE;
2063 void glyph_node::ascii_print(ascii_output_file *ascii)
2065 unsigned char c = ci->get_ascii_code();
2069 ascii->outs(ci->nm.contents());
2072 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2073 node *gn1, node *gn2, node *x)
2074 : glyph_node(c, t, gc, fc, x), n1(gn1), n2(gn2)
2079 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2080 hunits w, node *gn1, node *gn2, node *x)
2081 : glyph_node(c, t, gc, fc, w, x), n1(gn1), n2(gn2)
2086 ligature_node::~ligature_node()
2092 node *ligature_node::copy()
2095 return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy());
2097 return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy());
2101 void ligature_node::ascii_print(ascii_output_file *ascii)
2103 n1->ascii_print(ascii);
2104 n2->ascii_print(ascii);
2107 hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail)
2109 return n1->get_hyphen_list(n2->get_hyphen_list(tail));
2112 node *ligature_node::add_self(node *n, hyphen_list **p)
2114 n = n1->add_self(n, p);
2115 n = n2->add_self(n, p);
2121 kern_pair_node::kern_pair_node(hunits n, node *first, node *second, node *x)
2122 : node(x), amount(n), n1(first), n2(second)
2126 dbreak_node::dbreak_node(node *n, node *p, node *x)
2127 : node(x), none(n), pre(p), post(0)
2131 node *dbreak_node::merge_glyph_node(glyph_node *gn)
2133 glyph_node *gn2 = (glyph_node *)gn->copy();
2134 node *new_none = none ? none->merge_glyph_node(gn) : 0;
2135 node *new_post = post ? post->merge_glyph_node(gn2) : 0;
2136 if (new_none == 0 && new_post == 0) {
2155 node *kern_pair_node::merge_glyph_node(glyph_node *gn)
2157 node *nd = n2->merge_glyph_node(gn);
2161 nd = n2->merge_self(n1);
2172 hunits kern_pair_node::italic_correction()
2174 return n2->italic_correction();
2177 hunits kern_pair_node::subscript_correction()
2179 return n2->subscript_correction();
2182 void kern_pair_node::vertical_extent(vunits *min, vunits *max)
2184 n1->vertical_extent(min, max);
2186 n2->vertical_extent(&min2, &max2);
2193 node *kern_pair_node::add_discretionary_hyphen()
2195 tfont *tf = n2->get_tfont();
2197 if (tf->contains(soft_hyphen_char)) {
2198 color *gcol = n2->get_glyph_color();
2199 color *fcol = n2->get_fill_color();
2203 glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol);
2204 node *nn = n->merge_glyph_node(gn);
2209 return new dbreak_node(this, nn, next1);
2215 kern_pair_node::~kern_pair_node()
2223 dbreak_node::~dbreak_node()
2225 delete_node_list(pre);
2226 delete_node_list(post);
2227 delete_node_list(none);
2230 node *kern_pair_node::copy()
2232 return new kern_pair_node(amount, n1->copy(), n2->copy());
2235 node *copy_node_list(node *n)
2239 node *nn = n->copy();
2253 void delete_node_list(node *n)
2262 node *dbreak_node::copy()
2264 dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre));
2265 p->post = copy_node_list(post);
2269 hyphen_list *node::get_hyphen_list(hyphen_list *tail)
2274 hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail)
2276 return n1->get_hyphen_list(n2->get_hyphen_list(tail));
2279 class hyphen_inhibitor_node : public node {
2281 hyphen_inhibitor_node(node *nd = 0);
2286 hyphenation_type get_hyphenation_type();
2289 hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd)
2293 node *hyphen_inhibitor_node::copy()
2295 return new hyphen_inhibitor_node;
2298 int hyphen_inhibitor_node::same(node *)
2303 const char *hyphen_inhibitor_node::type()
2305 return "hyphen_inhibitor_node";
2308 int hyphen_inhibitor_node::force_tprint()
2313 hyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
2315 return HYPHEN_INHIBIT;
2318 /* add_discretionary_hyphen methods */
2320 node *dbreak_node::add_discretionary_hyphen()
2323 post = post->add_discretionary_hyphen();
2325 none = none->add_discretionary_hyphen();
2329 node *node::add_discretionary_hyphen()
2331 tfont *tf = get_tfont();
2333 return new hyphen_inhibitor_node(this);
2334 if (tf->contains(soft_hyphen_char)) {
2335 color *gcol = get_glyph_color();
2336 color *fcol = get_fill_color();
2340 glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol);
2341 node *n1 = n->merge_glyph_node(gn);
2346 return new dbreak_node(this, n1, next1);
2351 node *node::merge_self(node *)
2356 node *node::add_self(node *n, hyphen_list ** /*p*/)
2362 node *kern_pair_node::add_self(node *n, hyphen_list **p)
2364 n = n1->add_self(n, p);
2365 n = n2->add_self(n, p);
2371 hunits node::width()
2376 node *node::last_char_node()
2381 int node::force_tprint()
2386 hunits hmotion_node::width()
2393 return points_to_units(10);
2396 hunits kern_pair_node::width()
2398 return n1->width() + n2->width() + amount;
2401 node *kern_pair_node::last_char_node()
2403 node *nd = n2->last_char_node();
2406 return n1->last_char_node();
2409 hunits dbreak_node::width()
2412 for (node *n = none; n != 0; n = n->next)
2417 node *dbreak_node::last_char_node()
2419 for (node *n = none; n; n = n->next) {
2420 node *last = n->last_char_node();
2427 hunits dbreak_node::italic_correction()
2429 return none ? none->italic_correction() : H0;
2432 hunits dbreak_node::subscript_correction()
2434 return none ? none->subscript_correction() : H0;
2437 class italic_corrected_node : public node {
2441 italic_corrected_node(node *, hunits, node * = 0);
2442 ~italic_corrected_node();
2444 void ascii_print(ascii_output_file *);
2445 void asciify(macro *);
2447 node *last_char_node();
2448 void vertical_extent(vunits *, vunits *);
2449 int ends_sentence();
2450 int overlaps_horizontally();
2451 int overlaps_vertically();
2453 hyphenation_type get_hyphenation_type();
2455 hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
2456 int character_type();
2457 void tprint(troff_output_file *);
2458 hunits subscript_correction();
2460 node *add_self(node *, hyphen_list **);
2465 node *node::add_italic_correction(hunits *width)
2467 hunits ic = italic_correction();
2474 return new italic_corrected_node(this, ic, next1);
2478 italic_corrected_node::italic_corrected_node(node *nn, hunits xx, node *p)
2479 : node(p), n(nn), x(xx)
2484 italic_corrected_node::~italic_corrected_node()
2489 node *italic_corrected_node::copy()
2491 return new italic_corrected_node(n->copy(), x);
2494 hunits italic_corrected_node::width()
2496 return n->width() + x;
2499 void italic_corrected_node::vertical_extent(vunits *min, vunits *max)
2501 n->vertical_extent(min, max);
2504 void italic_corrected_node::tprint(troff_output_file *out)
2510 hunits italic_corrected_node::skew()
2512 return n->skew() - x/2;
2515 hunits italic_corrected_node::subscript_correction()
2517 return n->subscript_correction() - x;
2520 void italic_corrected_node::ascii_print(ascii_output_file *out)
2522 n->ascii_print(out);
2525 int italic_corrected_node::ends_sentence()
2527 return n->ends_sentence();
2530 int italic_corrected_node::overlaps_horizontally()
2532 return n->overlaps_horizontally();
2535 int italic_corrected_node::overlaps_vertically()
2537 return n->overlaps_vertically();
2540 node *italic_corrected_node::last_char_node()
2542 return n->last_char_node();
2545 tfont *italic_corrected_node::get_tfont()
2547 return n->get_tfont();
2550 hyphenation_type italic_corrected_node::get_hyphenation_type()
2552 return n->get_hyphenation_type();
2555 node *italic_corrected_node::add_self(node *nd, hyphen_list **p)
2557 nd = n->add_self(nd, p);
2558 hunits not_interested;
2559 nd = nd->add_italic_correction(¬_interested);
2565 hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail)
2567 return n->get_hyphen_list(tail);
2570 int italic_corrected_node::character_type()
2572 return n->character_type();
2575 class break_char_node : public node {
2580 break_char_node(node *, int, color *, node * = 0);
2584 vunits vertical_width();
2585 node *last_char_node();
2586 int character_type();
2587 int ends_sentence();
2588 node *add_self(node *, hyphen_list **);
2589 hyphen_list *get_hyphen_list(hyphen_list *s = 0);
2590 void tprint(troff_output_file *);
2591 void zero_width_tprint(troff_output_file *);
2592 void ascii_print(ascii_output_file *);
2593 void asciify(macro *);
2594 hyphenation_type get_hyphenation_type();
2595 int overlaps_vertically();
2596 int overlaps_horizontally();
2604 break_char_node::break_char_node(node *n, int bc, color *c, node *x)
2605 : node(x), ch(n), break_code(bc), col(c)
2609 break_char_node::~break_char_node()
2614 node *break_char_node::copy()
2616 return new break_char_node(ch->copy(), break_code, col);
2619 hunits break_char_node::width()
2624 vunits break_char_node::vertical_width()
2626 return ch->vertical_width();
2629 node *break_char_node::last_char_node()
2631 return ch->last_char_node();
2634 int break_char_node::character_type()
2636 return ch->character_type();
2639 int break_char_node::ends_sentence()
2641 return ch->ends_sentence();
2644 node *break_char_node::add_self(node *n, hyphen_list **p)
2646 assert((*p)->hyphenation_code == 0);
2647 if ((*p)->breakable && (break_code & 1)) {
2648 n = new space_node(H0, col, n);
2653 if ((*p)->breakable && (break_code & 2)) {
2654 n = new space_node(H0, col, n);
2657 hyphen_list *pp = *p;
2663 hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail)
2665 return new hyphen_list(0, tail);
2668 hyphenation_type break_char_node::get_hyphenation_type()
2670 return HYPHEN_MIDDLE;
2673 void break_char_node::ascii_print(ascii_output_file *ascii)
2675 ch->ascii_print(ascii);
2678 int break_char_node::overlaps_vertically()
2680 return ch->overlaps_vertically();
2683 int break_char_node::overlaps_horizontally()
2685 return ch->overlaps_horizontally();
2688 units break_char_node::size()
2693 tfont *break_char_node::get_tfont()
2695 return ch->get_tfont();
2698 node *extra_size_node::copy()
2700 return new extra_size_node(n);
2703 node *vertical_size_node::copy()
2705 return new vertical_size_node(n);
2708 node *hmotion_node::copy()
2710 return new hmotion_node(n, was_tab, unformat, col);
2713 node *space_char_hmotion_node::copy()
2715 return new space_char_hmotion_node(n, col);
2718 node *vmotion_node::copy()
2720 return new vmotion_node(n, col);
2723 node *dummy_node::copy()
2725 return new dummy_node;
2728 node *transparent_dummy_node::copy()
2730 return new transparent_dummy_node;
2733 hline_node::~hline_node()
2739 node *hline_node::copy()
2741 return new hline_node(x, n ? n->copy() : 0);
2744 hunits hline_node::width()
2746 return x < H0 ? H0 : x;
2749 vline_node::~vline_node()
2755 node *vline_node::copy()
2757 return new vline_node(x, n ? n->copy() : 0);
2760 hunits vline_node::width()
2762 return n == 0 ? H0 : n->width();
2765 zero_width_node::zero_width_node(node *nd) : n(nd)
2769 zero_width_node::~zero_width_node()
2771 delete_node_list(n);
2774 node *zero_width_node::copy()
2776 return new zero_width_node(copy_node_list(n));
2779 int node_list_character_type(node *p)
2782 for (; p; p = p->next)
2783 t |= p->character_type();
2787 int zero_width_node::character_type()
2789 return node_list_character_type(n);
2792 void node_list_vertical_extent(node *p, vunits *min, vunits *max)
2796 vunits cur_vpos = V0;
2798 for (; p; p = p->next) {
2799 p->vertical_extent(&v1, &v2);
2806 cur_vpos += p->vertical_width();
2810 void zero_width_node::vertical_extent(vunits *min, vunits *max)
2812 node_list_vertical_extent(n, min, max);
2815 overstrike_node::overstrike_node() : list(0), max_width(H0)
2819 overstrike_node::~overstrike_node()
2821 delete_node_list(list);
2824 node *overstrike_node::copy()
2826 overstrike_node *on = new overstrike_node;
2827 for (node *tem = list; tem; tem = tem->next)
2828 on->overstrike(tem->copy());
2832 void overstrike_node::overstrike(node *n)
2836 hunits w = n->width();
2840 for (p = &list; *p; p = &(*p)->next)
2846 hunits overstrike_node::width()
2851 bracket_node::bracket_node() : list(0), max_width(H0)
2855 bracket_node::~bracket_node()
2857 delete_node_list(list);
2860 node *bracket_node::copy()
2862 bracket_node *on = new bracket_node;
2867 for (tem = list; tem; tem = tem->next) {
2869 tem->next->last = tem;
2872 for (tem = last; tem; tem = tem->last)
2873 on->bracket(tem->copy());
2877 void bracket_node::bracket(node *n)
2881 hunits w = n->width();
2888 hunits bracket_node::width()
2898 int node::merge_space(hunits, hunits, hunits)
2904 space_node *space_node::free_list = 0;
2906 void *space_node::operator new(size_t n)
2908 assert(n == sizeof(space_node));
2910 free_list = (space_node *)new char[sizeof(space_node)*BLOCK];
2911 for (int i = 0; i < BLOCK - 1; i++)
2912 free_list[i].next = free_list + i + 1;
2913 free_list[BLOCK-1].next = 0;
2915 space_node *p = free_list;
2916 free_list = (space_node *)(free_list->next);
2921 inline void space_node::operator delete(void *p)
2924 ((space_node *)p)->next = free_list;
2925 free_list = (space_node *)p;
2930 space_node::space_node(hunits nn, color *c, node *p)
2931 : node(p), n(nn), set(0), was_escape_colon(0), col(c)
2935 space_node::space_node(hunits nn, int s, int flag, color *c, node *p)
2936 : node(p), n(nn), set(s), was_escape_colon(flag), col(c)
2941 space_node::~space_node()
2946 node *space_node::copy()
2948 return new space_node(n, set, was_escape_colon, col);
2951 int space_node::force_tprint()
2956 int space_node::nspaces()
2961 int space_node::merge_space(hunits h, hunits, hunits)
2967 hunits space_node::width()
2972 void node::spread_space(int*, hunits*)
2976 void space_node::spread_space(int *nspaces, hunits *desired_space)
2979 assert(*nspaces > 0);
2980 if (*nspaces == 1) {
2981 n += *desired_space;
2982 *desired_space = H0;
2985 hunits extra = *desired_space / *nspaces;
2986 *desired_space -= extra;
2994 void node::freeze_space()
2998 void space_node::freeze_space()
3003 void node::is_escape_colon()
3007 void space_node::is_escape_colon()
3009 was_escape_colon = 1;
3012 diverted_space_node::diverted_space_node(vunits d, node *p)
3017 node *diverted_space_node::copy()
3019 return new diverted_space_node(n);
3022 diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p)
3023 : node(p), filename(s)
3027 node *diverted_copy_file_node::copy()
3029 return new diverted_copy_file_node(filename);
3032 int node::ends_sentence()
3037 int kern_pair_node::ends_sentence()
3039 switch (n2->ends_sentence()) {
3049 return n1->ends_sentence();
3052 int node_list_ends_sentence(node *n)
3054 for (; n != 0; n = n->next)
3055 switch (n->ends_sentence()) {
3068 int dbreak_node::ends_sentence()
3070 return node_list_ends_sentence(none);
3073 int node::overlaps_horizontally()
3078 int node::overlaps_vertically()
3083 int node::discardable()
3088 int space_node::discardable()
3093 vunits node::vertical_width()
3098 vunits vline_node::vertical_width()
3103 vunits vmotion_node::vertical_width()
3108 int node::set_unformat_flag()
3113 int node::character_type()
3118 hunits node::subscript_correction()
3123 hunits node::italic_correction()
3128 hunits node::left_italic_correction()
3138 /* vertical_extent methods */
3140 void node::vertical_extent(vunits *min, vunits *max)
3142 vunits v = vertical_width();
3153 void vline_node::vertical_extent(vunits *min, vunits *max)
3156 node::vertical_extent(min, max);
3159 n->vertical_extent(&cmin, &cmax);
3160 vunits h = n->size();
3167 // we print the first character and then move up, so
3169 // we print the last character and then move up h
3182 // we move down by h and then print the first character, so
3192 /* ascii_print methods */
3194 static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n)
3198 ascii_print_reverse_node_list(ascii, n->next);
3199 n->ascii_print(ascii);
3202 void dbreak_node::ascii_print(ascii_output_file *ascii)
3204 ascii_print_reverse_node_list(ascii, none);
3207 void kern_pair_node::ascii_print(ascii_output_file *ascii)
3209 n1->ascii_print(ascii);
3210 n2->ascii_print(ascii);
3213 void node::ascii_print(ascii_output_file *)
3217 void space_node::ascii_print(ascii_output_file *ascii)
3223 void hmotion_node::ascii_print(ascii_output_file *ascii)
3225 // this is pretty arbitrary
3226 if (n >= points_to_units(2))
3230 void space_char_hmotion_node::ascii_print(ascii_output_file *ascii)
3235 /* asciify methods */
3237 void node::asciify(macro *m)
3242 void glyph_node::asciify(macro *m)
3244 unsigned char c = ci->get_asciify_code();
3246 c = ci->get_ascii_code();
3255 void kern_pair_node::asciify(macro *m)
3263 static void asciify_reverse_node_list(macro *m, node *n)
3267 asciify_reverse_node_list(m, n->next);
3271 void dbreak_node::asciify(macro *m)
3273 asciify_reverse_node_list(m, none);
3278 void ligature_node::asciify(macro *m)
3286 void break_char_node::asciify(macro *m)
3293 void italic_corrected_node::asciify(macro *m)
3300 void left_italic_corrected_node::asciify(macro *m)
3309 void hmotion_node::asciify(macro *m)
3319 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3321 : hmotion_node(i, c, next)
3325 void space_char_hmotion_node::asciify(macro *m)
3327 m->append(ESCAPE_SPACE);
3331 void space_node::asciify(macro *m)
3333 if (was_escape_colon) {
3334 m->append(ESCAPE_COLON);
3341 void word_space_node::asciify(macro *m)
3343 for (width_list *w = orig_width; w; w = w->next)
3348 void unbreakable_space_node::asciify(macro *m)
3350 m->append(ESCAPE_TILDE);
3354 void line_start_node::asciify(macro *)
3359 void vertical_size_node::asciify(macro *)
3364 breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/,
3365 breakpoint *rest, int /*is_inner*/)
3375 breakpoint *space_node::get_breakpoints(hunits width, int ns,
3376 breakpoint *rest, int is_inner)
3378 if (next->discardable())
3380 breakpoint *bp = new breakpoint;
3387 bp->index = rest->index + 1;
3397 int space_node::nbreaks()
3399 if (next->discardable())
3405 static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp,
3406 int ns, breakpoint *rest)
3409 rest = p->get_breakpoints(*widthp,
3411 node_list_get_breakpoints(p->next, widthp, ns,
3414 *widthp += p->width();
3419 breakpoint *dbreak_node::get_breakpoints(hunits width, int ns,
3420 breakpoint *rest, int is_inner)
3422 breakpoint *bp = new breakpoint;
3425 for (node *tem = pre; tem != 0; tem = tem->next)
3426 bp->width += tem->width();
3431 bp->index = rest->index + 1;
3438 return node_list_get_breakpoints(none, &width, ns, bp);
3441 int dbreak_node::nbreaks()
3444 for (node *tem = none; tem != 0; tem = tem->next)
3445 i += tem->nbreaks();
3449 void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/)
3454 void space_node::split(int where, node **pre, node **post)
3462 static void node_list_split(node *p, int *wherep, node **prep, node **postp)
3466 int nb = p->nbreaks();
3467 node_list_split(p->next, wherep, prep, postp);
3472 else if (*wherep < nb) {
3474 p->split(*wherep, prep, postp);
3483 void dbreak_node::split(int where, node **prep, node **postp)
3493 for (tem = pre; tem->next != 0; tem = tem->next)
3504 node_list_split(none, &where, prep, postp);
3510 hyphenation_type node::get_hyphenation_type()
3512 return HYPHEN_BOUNDARY;
3515 hyphenation_type dbreak_node::get_hyphenation_type()
3517 return HYPHEN_INHIBIT;
3520 hyphenation_type kern_pair_node::get_hyphenation_type()
3522 return HYPHEN_MIDDLE;
3525 hyphenation_type dummy_node::get_hyphenation_type()
3527 return HYPHEN_MIDDLE;
3530 hyphenation_type transparent_dummy_node::get_hyphenation_type()
3532 return HYPHEN_MIDDLE;
3535 hyphenation_type hmotion_node::get_hyphenation_type()
3537 return HYPHEN_MIDDLE;
3540 hyphenation_type space_char_hmotion_node::get_hyphenation_type()
3542 return HYPHEN_MIDDLE;
3545 hyphenation_type overstrike_node::get_hyphenation_type()
3547 return HYPHEN_MIDDLE;
3550 hyphenation_type space_node::get_hyphenation_type()
3552 if (was_escape_colon)
3553 return HYPHEN_MIDDLE;
3554 return HYPHEN_BOUNDARY;
3557 hyphenation_type unbreakable_space_node::get_hyphenation_type()
3559 return HYPHEN_MIDDLE;
3562 int node::interpret(macro *)
3567 special_node::special_node(const macro &m, int n)
3568 : mac(m), no_init_string(n)
3570 font_size fs = curenv->get_font_size();
3571 int char_height = curenv->get_char_height();
3572 int char_slant = curenv->get_char_slant();
3573 int fontno = env_definite_font(curenv);
3574 tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno);
3575 if (curenv->is_composite())
3576 tf = tf->get_plain();
3577 gcol = curenv->get_glyph_color();
3578 fcol = curenv->get_fill_color();
3581 special_node::special_node(const macro &m, tfont *t,
3582 color *gc, color *fc, int n)
3583 : mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n)
3587 int special_node::same(node *n)
3589 return mac == ((special_node *)n)->mac
3590 && tf == ((special_node *)n)->tf
3591 && gcol == ((special_node *)n)->gcol
3592 && fcol == ((special_node *)n)->fcol
3593 && no_init_string == ((special_node *)n)->no_init_string;
3596 const char *special_node::type()
3598 return "special_node";
3601 int special_node::ends_sentence()
3606 int special_node::force_tprint()
3611 node *special_node::copy()
3613 return new special_node(mac, tf, gcol, fcol, no_init_string);
3616 void special_node::tprint_start(troff_output_file *out)
3618 out->start_special(tf, gcol, fcol, no_init_string);
3621 void special_node::tprint_char(troff_output_file *out, unsigned char c)
3623 out->special_char(c);
3626 void special_node::tprint_end(troff_output_file *out)
3631 tfont *special_node::get_tfont()
3638 suppress_node::suppress_node(int on_or_off, int issue_limits)
3639 : is_on(on_or_off), emit_limits(issue_limits),
3640 filename(0), position(0), image_id(0)
3644 suppress_node::suppress_node(symbol f, char p, int id)
3645 : is_on(2), emit_limits(0), filename(f), position(p), image_id(id)
3649 suppress_node::suppress_node(int issue_limits, int on_or_off,
3650 symbol f, char p, int id)
3651 : is_on(on_or_off), emit_limits(issue_limits),
3652 filename(f), position(p), image_id(id)
3656 int suppress_node::same(node *n)
3658 return ((is_on == ((suppress_node *)n)->is_on)
3659 && (emit_limits == ((suppress_node *)n)->emit_limits)
3660 && (filename == ((suppress_node *)n)->filename)
3661 && (position == ((suppress_node *)n)->position)
3662 && (image_id == ((suppress_node *)n)->image_id));
3665 const char *suppress_node::type()
3667 return "suppress_node";
3670 node *suppress_node::copy()
3672 return new suppress_node(emit_limits, is_on, filename, position, image_id);
3675 int get_reg_int(const char *p)
3677 reg *r = (reg *)number_reg_dictionary.lookup(p);
3679 if (r && (r->get_value(&prev_value)))
3680 return (int)prev_value;
3682 warning(WARN_REG, "number register `%1' not defined", p);
3686 const char *get_reg_str(const char *p)
3688 reg *r = (reg *)number_reg_dictionary.lookup(p);
3690 return r->get_string();
3692 warning(WARN_REG, "register `%1' not defined", p);
3696 void suppress_node::put(troff_output_file *out, const char *s)
3699 while (s[i] != (char)0) {
3700 out->special_char(s[i]);
3706 * We need to remember the start of the image and its name.
3709 static char last_position = 0;
3710 static const char *last_image_filename = 0;
3711 static int last_image_id = 0;
3713 inline int min(int a, int b)
3715 return a < b ? a : b;
3719 * tprint - if (is_on == 2)
3720 * remember current position (l, r, c, i) and filename
3726 * emit postscript bounds for image
3728 * if (suppress boolean differs from current state)
3731 * record current page
3732 * set low water mark.
3735 void suppress_node::tprint(troff_output_file *out)
3737 int current_page = topdiv->get_page_number();
3738 // firstly check to see whether this suppress node contains
3739 // an image filename & position.
3741 // remember position and filename
3742 last_position = position;
3743 last_image_filename = strdup(filename.contents());
3744 last_image_id = image_id;
3745 // printf("start of image and page = %d\n", current_page);
3748 // now check whether the suppress node requires us to issue limits.
3751 // remember that the filename will contain a %d in which the
3752 // last_image_id is placed
3753 sprintf(name, last_image_filename, last_image_id);
3755 switch (last_position) {
3757 out->start_special();
3758 put(out, "html-tag:.centered-image");
3761 out->start_special();
3762 put(out, "html-tag:.right-image");
3765 out->start_special();
3766 put(out, "html-tag:.left-image");
3774 out->start_special();
3775 put(out, "html-tag:.auto-image ");
3780 // postscript (or other device)
3781 if (suppress_start_page > 0 && current_page != suppress_start_page)
3782 error("suppression limit registers span more than one page;\n"
3783 "image description %1 will be wrong", image_no);
3784 // if (topdiv->get_page_number() != suppress_start_page)
3785 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
3786 // topdiv->get_page_number(), suppress_start_page);
3788 // remember that the filename will contain a %d in which the
3789 // image_no is placed
3791 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
3792 topdiv->get_page_number(),
3793 get_reg_int("opminx"), get_reg_int("opminy"),
3794 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
3795 // page offset + line length
3796 get_reg_int(".o") + get_reg_int(".l"),
3797 name, hresolution, vresolution, get_reg_str(".F"));
3804 // lastly we reset the output registers
3805 reset_output_registers(out->get_vpos());
3809 suppress_start_page = current_page;
3814 int suppress_node::force_tprint()
3819 hunits suppress_node::width()
3824 /* composite_node */
3826 class composite_node : public charinfo_node {
3830 composite_node(node *, charinfo *, tfont *, node * = 0);
3834 node *last_char_node();
3836 void tprint(troff_output_file *);
3837 hyphenation_type get_hyphenation_type();
3838 void ascii_print(ascii_output_file *);
3839 void asciify(macro *);
3840 hyphen_list *get_hyphen_list(hyphen_list *tail);
3841 node *add_self(node *, hyphen_list **);
3846 void vertical_extent(vunits *, vunits *);
3847 vunits vertical_width();
3850 composite_node::composite_node(node *p, charinfo *c, tfont *t, node *x)
3851 : charinfo_node(c, x), n(p), tf(t)
3855 composite_node::~composite_node()
3857 delete_node_list(n);
3860 node *composite_node::copy()
3862 return new composite_node(copy_node_list(n), ci, tf);
3865 hunits composite_node::width()
3868 if (tf->get_constant_space(&x))
3871 for (node *tem = n; tem; tem = tem->next)
3874 if (tf->get_bold(&offset))
3876 x += tf->get_track_kern();
3880 node *composite_node::last_char_node()
3885 vunits composite_node::vertical_width()
3888 for (node *tem = n; tem; tem = tem->next)
3889 v += tem->vertical_width();
3893 units composite_node::size()
3895 return tf->get_size().to_units();
3898 hyphenation_type composite_node::get_hyphenation_type()
3900 return HYPHEN_MIDDLE;
3903 void composite_node::asciify(macro *m)
3905 unsigned char c = ci->get_asciify_code();
3907 c = ci->get_ascii_code();
3916 void composite_node::ascii_print(ascii_output_file *ascii)
3918 unsigned char c = ci->get_ascii_code();
3922 ascii->outs(ci->nm.contents());
3926 hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail)
3928 return new hyphen_list(ci->get_hyphenation_code(), tail);
3931 node *composite_node::add_self(node *nn, hyphen_list **p)
3933 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
3937 nn = nn->add_discretionary_hyphen();
3938 hyphen_list *pp = *p;
3944 tfont *composite_node::get_tfont()
3949 node *reverse_node_list(node *n)
3961 void composite_node::vertical_extent(vunits *min, vunits *max)
3963 n = reverse_node_list(n);
3964 node_list_vertical_extent(n, min, max);
3965 n = reverse_node_list(n);
3968 width_list::width_list(hunits w, hunits s)
3969 : width(w), sentence_width(s), next(0)
3973 width_list::width_list(width_list *w)
3974 : width(w->width), sentence_width(w->sentence_width), next(0)
3978 word_space_node::word_space_node(hunits d, color *c, width_list *w, node *x)
3979 : space_node(d, c, x), orig_width(w), unformat(0)
3983 word_space_node::word_space_node(hunits d, int s, color *c, width_list *w,
3985 : space_node(d, s, 0, c, x), orig_width(w), unformat(flag)
3989 word_space_node::~word_space_node()
3991 width_list *w = orig_width;
3993 width_list *tmp = w;
3999 node *word_space_node::copy()
4001 assert(orig_width != 0);
4002 width_list *w_old_curr = orig_width;
4003 width_list *w_new_curr = new width_list(w_old_curr);
4004 width_list *w_new = w_new_curr;
4005 w_old_curr = w_old_curr->next;
4006 while (w_old_curr != 0) {
4007 w_new_curr->next = new width_list(w_old_curr);
4008 w_new_curr = w_new_curr->next;
4009 w_old_curr = w_old_curr->next;
4011 return new word_space_node(n, set, col, w_new, unformat);
4014 int word_space_node::set_unformat_flag()
4020 void word_space_node::tprint(troff_output_file *out)
4022 out->fill_color(col);
4027 int word_space_node::merge_space(hunits h, hunits sw, hunits ssw)
4030 assert(orig_width != 0);
4031 width_list *w = orig_width;
4032 for (; w->next; w = w->next)
4034 w->next = new width_list(sw, ssw);
4038 unbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x)
4039 : word_space_node(d, c, 0, x)
4043 unbreakable_space_node::unbreakable_space_node(hunits d, int s,
4045 : word_space_node(d, s, c, 0, 0, x)
4049 node *unbreakable_space_node::copy()
4051 return new unbreakable_space_node(n, set, col);
4054 int unbreakable_space_node::force_tprint()
4059 breakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
4060 breakpoint *rest, int)
4065 int unbreakable_space_node::nbreaks()
4070 void unbreakable_space_node::split(int, node **, node **)
4075 int unbreakable_space_node::merge_space(hunits, hunits, hunits)
4084 draw_node::draw_node(char c, hvpair *p, int np, font_size s,
4085 color *gc, color *fc)
4086 : npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4088 point = new hvpair[npoints];
4089 for (int i = 0; i < npoints; i++)
4093 int draw_node::same(node *n)
4095 draw_node *nd = (draw_node *)n;
4096 if (code != nd->code || npoints != nd->npoints || sz != nd->sz
4097 || gcol != nd->gcol || fcol != nd->fcol)
4099 for (int i = 0; i < npoints; i++)
4100 if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
4105 const char *draw_node::type()
4110 int draw_node::force_tprint()
4115 draw_node::~draw_node()
4121 hunits draw_node::width()
4124 for (int i = 0; i < npoints; i++)
4129 vunits draw_node::vertical_width()
4134 for (int i = 0; i < npoints; i++)
4139 node *draw_node::copy()
4141 return new draw_node(code, point, npoints, sz, gcol, fcol);
4144 void draw_node::tprint(troff_output_file *out)
4146 out->draw(code, point, npoints, sz, gcol, fcol);
4149 /* tprint methods */
4151 void glyph_node::tprint(troff_output_file *out)
4153 tfont *ptf = tf->get_plain();
4155 out->put_char_width(ci, ptf, gcol, fcol, width(), H0);
4158 int bold = tf->get_bold(&offset);
4159 hunits w = ptf->get_width(ci);
4162 int cs = tf->get_constant_space(&x);
4172 k = tf->get_track_kern();
4174 out->put_char(ci, ptf, gcol, fcol);
4177 out->put_char_width(ci, ptf, gcol, fcol, w, k);
4181 void glyph_node::zero_width_tprint(troff_output_file *out)
4183 tfont *ptf = tf->get_plain();
4185 int bold = tf->get_bold(&offset);
4187 int cs = tf->get_constant_space(&x);
4189 x -= ptf->get_width(ci);
4195 out->put_char(ci, ptf, gcol, fcol);
4198 out->put_char(ci, ptf, gcol, fcol);
4199 out->right(-offset);
4205 void break_char_node::tprint(troff_output_file *t)
4210 void break_char_node::zero_width_tprint(troff_output_file *t)
4212 ch->zero_width_tprint(t);
4215 void hline_node::tprint(troff_output_file *out)
4225 hunits w = n->width();
4227 error("horizontal line drawing character must have positive width");
4238 out->right(xx - xx2);
4241 hunits rem = x - w*i;
4243 if (n->overlaps_horizontally()) {
4246 out->right(rem - w);
4256 void vline_node::tprint(troff_output_file *out)
4262 vunits h = n->size();
4263 int overlaps = n->overlaps_vertically();
4268 vunits rem = y - i*h;
4270 out->right(n->width());
4275 n->zero_width_tprint(out);
4279 n->zero_width_tprint(out);
4288 out->down(-h - rem);
4294 vunits rem = y - i*h;
4297 out->right(n->width());
4302 n->zero_width_tprint(out);
4305 n->zero_width_tprint(out);
4314 void zero_width_node::tprint(troff_output_file *out)
4319 n->zero_width_tprint(out);
4322 int hpos = out->get_hpos();
4323 int vpos = out->get_vpos();
4329 out->moveto(hpos, vpos);
4332 void overstrike_node::tprint(troff_output_file *out)
4335 for (node *tem = list; tem; tem = tem->next) {
4336 hunits x = (max_width - tem->width())/2;
4337 out->right(x - pos);
4339 tem->zero_width_tprint(out);
4341 out->right(max_width - pos);
4344 void bracket_node::tprint(troff_output_file *out)
4350 for (tem = list; tem; tem = tem->next)
4352 vunits h = list->size();
4353 vunits totalh = h*npieces;
4354 vunits y = (totalh - h)/2;
4356 for (tem = list; tem; tem = tem->next) {
4357 tem->zero_width_tprint(out);
4360 out->right(max_width);
4361 out->down(totalh - y);
4364 void node::tprint(troff_output_file *)
4368 void node::zero_width_tprint(troff_output_file *out)
4370 int hpos = out->get_hpos();
4371 int vpos = out->get_vpos();
4373 out->moveto(hpos, vpos);
4376 void space_node::tprint(troff_output_file *out)
4378 out->fill_color(col);
4382 void hmotion_node::tprint(troff_output_file *out)
4384 out->fill_color(col);
4388 void vmotion_node::tprint(troff_output_file *out)
4390 out->fill_color(col);
4394 void kern_pair_node::tprint(troff_output_file *out)
4401 static void tprint_reverse_node_list(troff_output_file *out, node *n)
4405 tprint_reverse_node_list(out, n->next);
4409 void dbreak_node::tprint(troff_output_file *out)
4411 tprint_reverse_node_list(out, none);
4414 void composite_node::tprint(troff_output_file *out)
4417 int is_bold = tf->get_bold(&bold_offset);
4418 hunits track_kern = tf->get_track_kern();
4419 hunits constant_space;
4420 int is_constant_spaced = tf->get_constant_space(&constant_space);
4422 if (is_constant_spaced) {
4424 for (node *tem = n; tem; tem = tem->next)
4433 int hpos = out->get_hpos();
4434 int vpos = out->get_vpos();
4435 tprint_reverse_node_list(out, n);
4436 out->moveto(hpos, vpos);
4437 out->right(bold_offset);
4439 tprint_reverse_node_list(out, n);
4440 if (is_constant_spaced)
4443 out->right(track_kern);
4446 node *make_composite_node(charinfo *s, environment *env)
4448 int fontno = env_definite_font(env);
4450 error("no current font");
4453 assert(fontno < font_table_size && font_table[fontno] != 0);
4454 node *n = charinfo_to_node_list(s, env);
4455 font_size fs = env->get_font_size();
4456 int char_height = env->get_char_height();
4457 int char_slant = env->get_char_slant();
4458 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
4460 if (env->is_composite())
4461 tf = tf->get_plain();
4462 return new composite_node(n, s, tf);
4465 node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
4467 int fontno = env_definite_font(env);
4469 error("no current font");
4472 assert(fontno < font_table_size && font_table[fontno] != 0);
4474 int found = font_table[fontno]->contains(s);
4476 if (s->is_fallback())
4477 return make_composite_node(s, env);
4478 if (s->numbered()) {
4479 if (!no_error_message)
4480 warning(WARN_CHAR, "can't find numbered character %1",
4484 special_font_list *sf = font_table[fontno]->sf;
4485 while (sf != 0 && !found) {
4488 found = font_table[fn]->contains(s);
4492 sf = global_special_fonts;
4493 while (sf != 0 && !found) {
4496 found = font_table[fn]->contains(s);
4502 && global_special_fonts == 0 && font_table[fontno]->sf == 0
4505 for (fn = 0; fn < font_table_size; fn++)
4507 && font_table[fn]->is_special()
4508 && font_table[fn]->contains(s)) {
4514 if (!no_error_message && s->first_time_not_found()) {
4515 unsigned char input_code = s->get_ascii_code();
4516 if (input_code != 0) {
4517 if (csgraph(input_code))
4518 warning(WARN_CHAR, "can't find character `%1'", input_code);
4520 warning(WARN_CHAR, "can't find character with input code %1",
4523 else if (s->nm.contents())
4524 warning(WARN_CHAR, "can't find special character `%1'",
4530 font_size fs = env->get_font_size();
4531 int char_height = env->get_char_height();
4532 int char_slant = env->get_char_slant();
4533 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
4534 if (env->is_composite())
4535 tf = tf->get_plain();
4536 color *gcol = env->get_glyph_color();
4537 color *fcol = env->get_fill_color();
4538 return new glyph_node(s, tf, gcol, fcol);
4541 node *make_node(charinfo *ci, environment *env)
4543 switch (ci->get_special_translation()) {
4544 case charinfo::TRANSLATE_SPACE:
4545 return new space_char_hmotion_node(env->get_space_width(),
4546 env->get_fill_color());
4547 case charinfo::TRANSLATE_STRETCHABLE_SPACE:
4548 return new unbreakable_space_node(env->get_space_width(),
4549 env->get_fill_color());
4550 case charinfo::TRANSLATE_DUMMY:
4551 return new dummy_node;
4552 case charinfo::TRANSLATE_HYPHEN_INDICATOR:
4553 error("translation to \\% ignored in this context");
4556 charinfo *tem = ci->get_translation();
4559 macro *mac = ci->get_macro();
4560 if (mac && !ci->is_fallback())
4561 return make_composite_node(ci, env);
4563 return make_glyph_node(ci, env);
4566 int character_exists(charinfo *ci, environment *env)
4568 if (ci->get_special_translation() != charinfo::TRANSLATE_NONE)
4570 charinfo *tem = ci->get_translation();
4573 if (ci->get_macro())
4575 node *nd = make_glyph_node(ci, env, 1);
4583 node *node::add_char(charinfo *ci, environment *env,
4584 hunits *widthp, int *spacep)
4587 switch (ci->get_special_translation()) {
4588 case charinfo::TRANSLATE_SPACE:
4589 res = new space_char_hmotion_node(env->get_space_width(),
4590 env->get_fill_color(), this);
4591 *widthp += res->width();
4593 case charinfo::TRANSLATE_STRETCHABLE_SPACE:
4594 res = new unbreakable_space_node(env->get_space_width(),
4595 env->get_fill_color(), this);
4596 res->freeze_space();
4597 *widthp += res->width();
4598 *spacep += res->nspaces();
4600 case charinfo::TRANSLATE_DUMMY:
4601 return new dummy_node(this);
4602 case charinfo::TRANSLATE_HYPHEN_INDICATOR:
4603 return add_discretionary_hyphen();
4605 charinfo *tem = ci->get_translation();
4608 macro *mac = ci->get_macro();
4609 if (mac && !ci->is_fallback()) {
4610 res = make_composite_node(ci, env);
4613 *widthp += res->width();
4619 node *gn = make_glyph_node(ci, env);
4623 hunits old_width = width();
4624 node *p = gn->merge_self(this);
4626 *widthp += gn->width();
4631 *widthp += p->width() - old_width;
4637 if (ci->can_break_before())
4639 if (ci->can_break_after())
4642 node *next1 = res->next;
4644 res = new break_char_node(res, break_code, env->get_fill_color(), next1);
4652 int same_node(node *n1, node *n2)
4656 return n1->type() == n2->type() && n1->same(n2);
4664 int same_node_list(node *n1, node *n2)
4667 if (n1->type() != n2->type() || !n1->same(n2))
4675 int extra_size_node::same(node *nd)
4677 return n == ((extra_size_node *)nd)->n;
4680 const char *extra_size_node::type()
4682 return "extra_size_node";
4685 int extra_size_node::force_tprint()
4690 int vertical_size_node::same(node *nd)
4692 return n == ((vertical_size_node *)nd)->n;
4695 const char *vertical_size_node::type()
4697 return "vertical_size_node";
4700 int vertical_size_node::set_unformat_flag()
4705 int vertical_size_node::force_tprint()
4710 int hmotion_node::same(node *nd)
4712 return n == ((hmotion_node *)nd)->n
4713 && col == ((hmotion_node *)nd)->col;
4716 const char *hmotion_node::type()
4718 return "hmotion_node";
4721 int hmotion_node::set_unformat_flag()
4727 int hmotion_node::force_tprint()
4732 node *hmotion_node::add_self(node *n, hyphen_list **p)
4735 hyphen_list *pp = *p;
4741 hyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail)
4743 return new hyphen_list(0, tail);
4746 int space_char_hmotion_node::same(node *nd)
4748 return n == ((space_char_hmotion_node *)nd)->n
4749 && col == ((space_char_hmotion_node *)nd)->col;
4752 const char *space_char_hmotion_node::type()
4754 return "space_char_hmotion_node";
4757 int space_char_hmotion_node::force_tprint()
4762 node *space_char_hmotion_node::add_self(node *n, hyphen_list **p)
4765 hyphen_list *pp = *p;
4771 hyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail)
4773 return new hyphen_list(0, tail);
4776 int vmotion_node::same(node *nd)
4778 return n == ((vmotion_node *)nd)->n
4779 && col == ((vmotion_node *)nd)->col;
4782 const char *vmotion_node::type()
4784 return "vmotion_node";
4787 int vmotion_node::force_tprint()
4792 int hline_node::same(node *nd)
4794 return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
4797 const char *hline_node::type()
4799 return "hline_node";
4802 int hline_node::force_tprint()
4807 int vline_node::same(node *nd)
4809 return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
4812 const char *vline_node::type()
4814 return "vline_node";
4817 int vline_node::force_tprint()
4822 int dummy_node::same(node * /*nd*/)
4827 const char *dummy_node::type()
4829 return "dummy_node";
4832 int dummy_node::force_tprint()
4837 int transparent_dummy_node::same(node * /*nd*/)
4842 const char *transparent_dummy_node::type()
4844 return "transparent_dummy_node";
4847 int transparent_dummy_node::force_tprint()
4852 int transparent_dummy_node::ends_sentence()
4857 int zero_width_node::same(node *nd)
4859 return same_node_list(n, ((zero_width_node *)nd)->n);
4862 const char *zero_width_node::type()
4864 return "zero_width_node";
4867 int zero_width_node::force_tprint()
4872 int italic_corrected_node::same(node *nd)
4874 return (x == ((italic_corrected_node *)nd)->x
4875 && same_node(n, ((italic_corrected_node *)nd)->n));
4878 const char *italic_corrected_node::type()
4880 return "italic_corrected_node";
4883 int italic_corrected_node::force_tprint()
4888 left_italic_corrected_node::left_italic_corrected_node(node *x)
4893 left_italic_corrected_node::~left_italic_corrected_node()
4898 node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn)
4901 hunits lic = gn->left_italic_correction();
4902 if (!lic.is_zero()) {
4909 node *nd = n->merge_glyph_node(gn);
4912 x = n->left_italic_correction();
4919 node *left_italic_corrected_node::copy()
4921 left_italic_corrected_node *nd = new left_italic_corrected_node;
4929 void left_italic_corrected_node::tprint(troff_output_file *out)
4937 const char *left_italic_corrected_node::type()
4939 return "left_italic_corrected_node";
4942 int left_italic_corrected_node::force_tprint()
4947 int left_italic_corrected_node::same(node *nd)
4949 return (x == ((left_italic_corrected_node *)nd)->x
4950 && same_node(n, ((left_italic_corrected_node *)nd)->n));
4953 void left_italic_corrected_node::ascii_print(ascii_output_file *out)
4956 n->ascii_print(out);
4959 hunits left_italic_corrected_node::width()
4961 return n ? n->width() + x : H0;
4964 void left_italic_corrected_node::vertical_extent(vunits *min, vunits *max)
4967 n->vertical_extent(min, max);
4969 node::vertical_extent(min, max);
4972 hunits left_italic_corrected_node::skew()
4974 return n ? n->skew() + x/2 : H0;
4977 hunits left_italic_corrected_node::subscript_correction()
4979 return n ? n->subscript_correction() : H0;
4982 hunits left_italic_corrected_node::italic_correction()
4984 return n ? n->italic_correction() : H0;
4987 int left_italic_corrected_node::ends_sentence()
4989 return n ? n->ends_sentence() : 0;
4992 int left_italic_corrected_node::overlaps_horizontally()
4994 return n ? n->overlaps_horizontally() : 0;
4997 int left_italic_corrected_node::overlaps_vertically()
4999 return n ? n->overlaps_vertically() : 0;
5002 node *left_italic_corrected_node::last_char_node()
5004 return n ? n->last_char_node() : 0;
5007 tfont *left_italic_corrected_node::get_tfont()
5009 return n ? n->get_tfont() : 0;
5012 hyphenation_type left_italic_corrected_node::get_hyphenation_type()
5015 return n->get_hyphenation_type();
5017 return HYPHEN_MIDDLE;
5020 hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail)
5022 return n ? n->get_hyphen_list(tail) : tail;
5025 node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p)
5028 nd = new left_italic_corrected_node(nd);
5029 nd = n->add_self(nd, p);
5036 int left_italic_corrected_node::character_type()
5038 return n ? n->character_type() : 0;
5041 int overstrike_node::same(node *nd)
5043 return same_node_list(list, ((overstrike_node *)nd)->list);
5046 const char *overstrike_node::type()
5048 return "overstrike_node";
5051 int overstrike_node::force_tprint()
5056 node *overstrike_node::add_self(node *n, hyphen_list **p)
5059 hyphen_list *pp = *p;
5065 hyphen_list *overstrike_node::get_hyphen_list(hyphen_list *tail)
5067 return new hyphen_list(0, tail);
5070 int bracket_node::same(node *nd)
5072 return same_node_list(list, ((bracket_node *)nd)->list);
5075 const char *bracket_node::type()
5077 return "bracket_node";
5080 int bracket_node::force_tprint()
5085 int composite_node::same(node *nd)
5087 return ci == ((composite_node *)nd)->ci
5088 && same_node_list(n, ((composite_node *)nd)->n);
5091 const char *composite_node::type()
5093 return "composite_node";
5096 int composite_node::force_tprint()
5101 int glyph_node::same(node *nd)
5103 return ci == ((glyph_node *)nd)->ci
5104 && tf == ((glyph_node *)nd)->tf
5105 && gcol == ((glyph_node *)nd)->gcol
5106 && fcol == ((glyph_node *)nd)->fcol;
5109 const char *glyph_node::type()
5111 return "glyph_node";
5114 int glyph_node::force_tprint()
5119 int ligature_node::same(node *nd)
5121 return (same_node(n1, ((ligature_node *)nd)->n1)
5122 && same_node(n2, ((ligature_node *)nd)->n2)
5123 && glyph_node::same(nd));
5126 const char *ligature_node::type()
5128 return "ligature_node";
5131 int ligature_node::force_tprint()
5136 int kern_pair_node::same(node *nd)
5138 return (amount == ((kern_pair_node *)nd)->amount
5139 && same_node(n1, ((kern_pair_node *)nd)->n1)
5140 && same_node(n2, ((kern_pair_node *)nd)->n2));
5143 const char *kern_pair_node::type()
5145 return "kern_pair_node";
5148 int kern_pair_node::force_tprint()
5153 int dbreak_node::same(node *nd)
5155 return (same_node_list(none, ((dbreak_node *)nd)->none)
5156 && same_node_list(pre, ((dbreak_node *)nd)->pre)
5157 && same_node_list(post, ((dbreak_node *)nd)->post));
5160 const char *dbreak_node::type()
5162 return "dbreak_node";
5165 int dbreak_node::force_tprint()
5170 int break_char_node::same(node *nd)
5172 return break_code == ((break_char_node *)nd)->break_code
5173 && col == ((break_char_node *)nd)->col
5174 && same_node(ch, ((break_char_node *)nd)->ch);
5177 const char *break_char_node::type()
5179 return "break_char_node";
5182 int break_char_node::force_tprint()
5187 int line_start_node::same(node * /*nd*/)
5192 const char *line_start_node::type()
5194 return "line_start_node";
5197 int line_start_node::force_tprint()
5202 int space_node::same(node *nd)
5204 return n == ((space_node *)nd)->n
5205 && set == ((space_node *)nd)->set
5206 && col == ((space_node *)nd)->col;
5209 const char *space_node::type()
5211 return "space_node";
5214 int word_space_node::same(node *nd)
5216 return n == ((word_space_node *)nd)->n
5217 && set == ((word_space_node *)nd)->set
5218 && col == ((word_space_node *)nd)->col;
5221 const char *word_space_node::type()
5223 return "word_space_node";
5226 int word_space_node::force_tprint()
5231 int unbreakable_space_node::same(node *nd)
5233 return n == ((unbreakable_space_node *)nd)->n
5234 && set == ((unbreakable_space_node *)nd)->set
5235 && col == ((unbreakable_space_node *)nd)->col;
5238 const char *unbreakable_space_node::type()
5240 return "unbreakable_space_node";
5243 node *unbreakable_space_node::add_self(node *n, hyphen_list **p)
5246 hyphen_list *pp = *p;
5252 hyphen_list *unbreakable_space_node::get_hyphen_list(hyphen_list *tail)
5254 return new hyphen_list(0, tail);
5257 int diverted_space_node::same(node *nd)
5259 return n == ((diverted_space_node *)nd)->n;
5262 const char *diverted_space_node::type()
5264 return "diverted_space_node";
5267 int diverted_space_node::force_tprint()
5272 int diverted_copy_file_node::same(node *nd)
5274 return filename == ((diverted_copy_file_node *)nd)->filename;
5277 const char *diverted_copy_file_node::type()
5279 return "diverted_copy_file_node";
5282 int diverted_copy_file_node::force_tprint()
5287 // Grow the font_table so that its size is > n.
5289 static void grow_font_table(int n)
5291 assert(n >= font_table_size);
5292 font_info **old_font_table = font_table;
5293 int old_font_table_size = font_table_size;
5294 font_table_size = font_table_size ? (font_table_size*3)/2 : 10;
5295 if (font_table_size <= n)
5296 font_table_size = n + 10;
5297 font_table = new font_info *[font_table_size];
5298 if (old_font_table_size)
5299 memcpy(font_table, old_font_table,
5300 old_font_table_size*sizeof(font_info *));
5301 a_delete old_font_table;
5302 for (int i = old_font_table_size; i < font_table_size; i++)
5306 dictionary font_translation_dictionary(17);
5308 static symbol get_font_translation(symbol nm)
5310 void *p = font_translation_dictionary.lookup(nm);
5311 return p ? symbol((char *)p) : nm;
5314 dictionary font_dictionary(50);
5316 static int mount_font_no_translate(int n, symbol name, symbol external_name)
5319 // We store the address of this char in font_dictionary to indicate
5320 // that we've previously tried to mount the font and failed.
5323 void *p = font_dictionary.lookup(external_name);
5326 fm = font::load_font(external_name.contents(), ¬_found);
5329 warning(WARN_FONT, "can't find font `%1'", external_name.contents());
5330 font_dictionary.lookup(external_name, &a_char);
5333 font_dictionary.lookup(name, fm);
5335 else if (p == &a_char) {
5337 error("invalid font `%1'", external_name.contents());
5343 if (n >= font_table_size) {
5344 if (n - font_table_size > 1000) {
5345 error("font position too much larger than first unused position");
5350 else if (font_table[n] != 0)
5351 delete font_table[n];
5352 font_table[n] = new font_info(name, n, external_name, fm);
5353 font_family::invalidate_fontno(n);
5357 int mount_font(int n, symbol name, symbol external_name)
5360 name = get_font_translation(name);
5361 if (external_name.is_null())
5362 external_name = name;
5364 external_name = get_font_translation(external_name);
5365 return mount_font_no_translate(n, name, external_name);
5368 void mount_style(int n, symbol name)
5371 if (n >= font_table_size) {
5372 if (n - font_table_size > 1000) {
5373 error("font position too much larger than first unused position");
5378 else if (font_table[n] != 0)
5379 delete font_table[n];
5380 font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0);
5381 font_family::invalidate_fontno(n);
5384 /* global functions */
5386 void font_translate()
5388 symbol from = get_name(1);
5389 if (!from.is_null()) {
5390 symbol to = get_name();
5391 if (to.is_null() || from == to)
5392 font_translation_dictionary.remove(from);
5394 font_translation_dictionary.lookup(from, (void *)to.contents());
5399 void font_position()
5402 if (get_integer(&n)) {
5404 error("negative font position");
5406 symbol internal_name = get_name(1);
5407 if (!internal_name.is_null()) {
5408 symbol external_name = get_long_name(0);
5409 mount_font(n, internal_name, external_name); // ignore error
5416 font_family::font_family(symbol s)
5417 : map_size(10), nm(s)
5419 map = new int[map_size];
5420 for (int i = 0; i < map_size; i++)
5424 font_family::~font_family()
5429 int font_family::make_definite(int i)
5432 if (i < map_size && map[i] >= 0)
5435 if (i < font_table_size && font_table[i] != 0) {
5436 if (i >= map_size) {
5437 int old_map_size = map_size;
5443 map = new int[map_size];
5444 memcpy(map, old_map, old_map_size*sizeof(int));
5446 for (int j = old_map_size; j < map_size; j++)
5449 if (font_table[i]->is_style()) {
5450 symbol sty = font_table[i]->get_name();
5451 symbol f = concat(nm, sty);
5453 // don't use symbol_fontno, because that might return a style
5454 // and because we don't want to translate the name
5455 for (n = 0; n < font_table_size; n++)
5456 if (font_table[n] != 0 && font_table[n]->is_named(f)
5457 && !font_table[n]->is_style())
5459 if (n >= font_table_size) {
5460 n = next_available_font_position();
5461 if (!mount_font_no_translate(n, f, f))
5477 dictionary family_dictionary(5);
5479 font_family *lookup_family(symbol nm)
5481 font_family *f = (font_family *)family_dictionary.lookup(nm);
5483 f = new font_family(nm);
5484 (void)family_dictionary.lookup(nm, f);
5489 void font_family::invalidate_fontno(int n)
5491 assert(n >= 0 && n < font_table_size);
5492 dictionary_iterator iter(family_dictionary);
5495 while (iter.get(&nm, (void **)&fam)) {
5496 int map_size = fam->map_size;
5499 for (int i = 0; i < map_size; i++)
5500 if (fam->map[i] == n)
5508 if (get_integer(&n)) {
5510 error("negative font position");
5512 symbol internal_name = get_name(1);
5513 if (!internal_name.is_null())
5514 mount_style(n, internal_name);
5520 static int get_fontno()
5524 if (tok.delimiter()) {
5525 symbol s = get_name(1);
5527 n = symbol_fontno(s);
5529 n = next_available_font_position();
5530 if (!mount_font(n, s))
5533 return curenv->get_family()->make_definite(n);
5536 else if (get_integer(&n)) {
5537 if (n < 0 || n >= font_table_size || font_table[n] == 0)
5538 error("bad font number");
5540 return curenv->get_family()->make_definite(n);
5545 static int underline_fontno = 2;
5547 void underline_font()
5549 int n = get_fontno();
5551 underline_fontno = n;
5555 int get_underline_fontno()
5557 return underline_fontno;
5560 static void read_special_fonts(special_font_list **sp)
5562 special_font_list *s = *sp;
5565 special_font_list *tem = s;
5569 special_font_list **p = sp;
5571 int i = get_fontno();
5573 special_font_list *tem = new special_font_list;
5582 void font_special_request()
5584 int n = get_fontno();
5586 read_special_fonts(&font_table[n]->sf);
5590 void special_request()
5592 read_special_fonts(&global_special_fonts);
5596 int next_available_font_position()
5599 for (i = 1; i < font_table_size && font_table[i] != 0; i++)
5604 int symbol_fontno(symbol s)
5606 s = get_font_translation(s);
5607 for (int i = 0; i < font_table_size; i++)
5608 if (font_table[i] != 0 && font_table[i]->is_named(s))
5613 int is_good_fontno(int n)
5615 return n >= 0 && n < font_table_size && font_table[n] != 0;
5618 int get_bold_fontno(int n)
5620 if (n >= 0 && n < font_table_size && font_table[n] != 0) {
5622 if (font_table[n]->get_bold(&offset))
5623 return offset.to_units() + 1;
5631 hunits env_digit_width(environment *env)
5633 node *n = make_glyph_node(charset_table['0'], env);
5635 hunits x = n->width();
5643 hunits env_space_width(environment *env)
5645 int fn = env_definite_font(env);
5646 font_size fs = env->get_font_size();
5647 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
5648 return scale(fs.to_units()/3, env->get_space_size(), 12);
5650 return font_table[fn]->get_space_width(fs, env->get_space_size());
5653 hunits env_sentence_space_width(environment *env)
5655 int fn = env_definite_font(env);
5656 font_size fs = env->get_font_size();
5657 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
5658 return scale(fs.to_units()/3, env->get_sentence_space_size(), 12);
5660 return font_table[fn]->get_space_width(fs, env->get_sentence_space_size());
5663 hunits env_half_narrow_space_width(environment *env)
5665 int fn = env_definite_font(env);
5666 font_size fs = env->get_font_size();
5667 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
5670 return font_table[fn]->get_half_narrow_space_width(fs);
5673 hunits env_narrow_space_width(environment *env)
5675 int fn = env_definite_font(env);
5676 font_size fs = env->get_font_size();
5677 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
5680 return font_table[fn]->get_narrow_space_width(fs);
5685 int n = get_fontno();
5688 if (tok.delimiter()) {
5689 int f = get_fontno();
5692 if (has_arg() && get_number(&offset, 'u') && offset >= 1)
5693 font_table[f]->set_conditional_bold(n, hunits(offset - 1));
5695 font_table[f]->conditional_unbold(n);
5700 if (get_number(&offset, 'u') && offset >= 1)
5701 font_table[n]->set_bold(hunits(offset - 1));
5703 font_table[n]->unbold();
5707 font_table[n]->unbold();
5712 track_kerning_function::track_kerning_function() : non_zero(0)
5716 track_kerning_function::track_kerning_function(int min_s, hunits min_a,
5717 int max_s, hunits max_a)
5718 : non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s),
5723 int track_kerning_function::operator==(const track_kerning_function &tk)
5727 && min_size == tk.min_size
5728 && min_amount == tk.min_amount
5729 && max_size == tk.max_size
5730 && max_amount == tk.max_amount);
5732 return !tk.non_zero;
5735 int track_kerning_function::operator!=(const track_kerning_function &tk)
5738 return (!tk.non_zero
5739 || min_size != tk.min_size
5740 || min_amount != tk.min_amount
5741 || max_size != tk.max_size
5742 || max_amount != tk.max_amount);
5747 hunits track_kerning_function::compute(int size)
5750 if (max_size <= min_size)
5752 else if (size <= min_size)
5754 else if (size >= max_size)
5757 return (scale(max_amount, size - min_size, max_size - min_size)
5758 + scale(min_amount, max_size - size, max_size - min_size));
5766 int n = get_fontno();
5769 hunits min_a, max_a;
5771 && get_number(&min_s, 'z')
5772 && get_hunits(&min_a, 'p')
5773 && get_number(&max_s, 'z')
5774 && get_hunits(&max_a, 'p')) {
5775 track_kerning_function tk(min_s, min_a, max_s, max_a);
5776 font_table[n]->set_track_kern(tk);
5779 track_kerning_function tk;
5780 font_table[n]->set_track_kern(tk);
5786 void constant_space()
5788 int n = get_fontno();
5791 if (!has_arg() || !get_integer(&x))
5792 font_table[n]->set_constant_space(CONSTANT_SPACE_NONE);
5794 if (!has_arg() || !get_number(&y, 'z'))
5795 font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x);
5797 font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE,
5809 if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2)
5810 global_ligature_mode = lig;
5812 global_ligature_mode = 1;
5819 if (has_arg() && get_integer(&k))
5820 global_kern_mode = k != 0;
5822 global_kern_mode = 1;
5826 void set_soft_hyphen_char()
5828 soft_hyphen_char = get_optional_char();
5829 if (!soft_hyphen_char)
5830 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
5836 if (suppress_output_flag)
5837 the_output = new suppress_output_file;
5838 else if (ascii_output_flag)
5839 the_output = new ascii_output_file;
5841 the_output = new troff_output_file;
5844 class next_available_font_position_reg : public reg {
5846 const char *get_string();
5849 const char *next_available_font_position_reg::get_string()
5851 return i_to_a(next_available_font_position());
5854 class printing_reg : public reg {
5856 const char *get_string();
5859 const char *printing_reg::get_string()
5862 return the_output->is_printing() ? "1" : "0";
5867 void init_node_requests()
5869 init_request("fp", font_position);
5870 init_request("sty", style);
5871 init_request("cs", constant_space);
5872 init_request("bd", bold_font);
5873 init_request("uf", underline_font);
5874 init_request("lg", ligature);
5875 init_request("kern", kern_request);
5876 init_request("tkf", track_kern);
5877 init_request("special", special_request);
5878 init_request("fspecial", font_special_request);
5879 init_request("ftr", font_translate);
5880 init_request("shc", set_soft_hyphen_char);
5881 number_reg_dictionary.define(".fp", new next_available_font_position_reg);
5882 number_reg_dictionary.define(".kern",
5883 new constant_int_reg(&global_kern_mode));
5884 number_reg_dictionary.define(".lg",
5885 new constant_int_reg(&global_ligature_mode));
5886 number_reg_dictionary.define(".P", new printing_reg);
5887 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);