2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
22 extern int debug_state
;
30 #include "dictionary.h"
32 #include "stringclass.h"
51 #else /* not _POSIX_VERSION */
53 /* traditional Unix */
55 #define WIFEXITED(s) (((s) & 0377) == 0)
56 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
57 #define WTERMSIG(s) ((s) & 0177)
58 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
59 #define WSTOPSIG(s) (((s) >> 8) & 0377)
60 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
62 #endif /* not _POSIX_VERSION */
64 // declarations to avoid friend name injections
67 tfont
*make_tfont(tfont_spec
&);
71 * how many boundaries of images have been written? Useful for
76 static int suppress_start_page
= 0;
80 symbol
HYPHEN_SYMBOL("hy");
82 // Character used when a hyphen is inserted at a line break.
83 static charinfo
*soft_hyphen_char
;
85 enum constant_space_type
{
87 CONSTANT_SPACE_RELATIVE
,
88 CONSTANT_SPACE_ABSOLUTE
91 struct special_font_list
{
93 special_font_list
*next
;
96 special_font_list
*global_special_fonts
;
97 static int global_ligature_mode
= 1;
98 static int global_kern_mode
= 1;
100 class track_kerning_function
{
107 track_kerning_function();
108 track_kerning_function(units
, hunits
, units
, hunits
);
109 int operator==(const track_kerning_function
&);
110 int operator!=(const track_kerning_function
&);
111 hunits
compute(int point_size
);
114 // embolden fontno when this is the current font
116 struct conditional_bold
{
117 conditional_bold
*next
;
120 conditional_bold(int, hunits
, conditional_bold
* = 0);
129 symbol internal_name
;
130 symbol external_name
;
134 track_kerning_function track_kern
;
135 constant_space_type is_constant_spaced
;
136 units constant_space
;
137 int last_ligature_mode
;
139 conditional_bold
*cond_bold_list
;
142 special_font_list
*sf
;
143 font_info(symbol
, int, symbol
, font
*);
144 int contains(charinfo
*);
145 void set_bold(hunits
);
147 void set_conditional_bold(int, hunits
);
148 void conditional_unbold(int);
149 void set_track_kern(track_kerning_function
&);
150 void set_constant_space(constant_space_type
, units
= 0);
151 int is_named(symbol
);
153 tfont
*get_tfont(font_size
, int, int, int);
154 hunits
get_space_width(font_size
, int);
155 hunits
get_narrow_space_width(font_size
);
156 hunits
get_half_narrow_space_width(font_size
);
157 int get_bold(hunits
*);
160 friend symbol
get_font_name(int, environment
*);
161 friend symbol
get_style_name(int);
171 char is_constant_spaced
;
175 hunits track_kern
; // add this to the width
176 hunits constant_space_width
;
180 tfont_spec(symbol
, int, font
*, font_size
, int, int);
181 tfont_spec(const tfont_spec
&spec
) { *this = spec
; }
183 int operator==(const tfont_spec
&);
184 friend tfont
*font_info::get_tfont(font_size fs
, int, int, int);
187 class tfont
: public tfont_spec
{
188 static tfont
*tfont_list
;
190 tfont
*plain_version
;
193 int contains(charinfo
*);
194 hunits
get_width(charinfo
*c
);
195 int get_bold(hunits
*);
196 int get_constant_space(hunits
*);
197 hunits
get_track_kern();
199 font_size
get_size();
201 charinfo
*get_lig(charinfo
*c1
, charinfo
*c2
);
202 int get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
);
203 int get_input_position();
204 int get_character_type(charinfo
*);
207 vunits
get_char_height(charinfo
*);
208 vunits
get_char_depth(charinfo
*);
209 hunits
get_char_skew(charinfo
*);
210 hunits
get_italic_correction(charinfo
*);
211 hunits
get_left_italic_correction(charinfo
*);
212 hunits
get_subscript_correction(charinfo
*);
213 friend tfont
*make_tfont(tfont_spec
&);
216 inline int env_definite_font(environment
*env
)
218 return env
->get_family()->make_definite(env
->get_font());
221 /* font_info functions */
223 static font_info
**font_table
= 0;
224 static int font_table_size
= 0;
226 font_info::font_info(symbol nm
, int n
, symbol enm
, font
*f
)
227 : last_tfont(0), number(n
), last_size(0),
228 internal_name(nm
), external_name(enm
), fm(f
),
229 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE
), last_ligature_mode(1),
230 last_kern_mode(1), cond_bold_list(0), sf(0)
234 inline int font_info::contains(charinfo
*ci
)
236 return fm
!= 0 && fm
->contains(ci
->get_index());
239 inline int font_info::is_special()
241 return fm
!= 0 && fm
->is_special();
244 inline int font_info::is_style()
249 tfont
*make_tfont(tfont_spec
&spec
)
251 for (tfont
*p
= tfont::tfont_list
; p
; p
= p
->next
)
254 return new tfont(spec
);
257 // this is the current_font, fontno is where we found the character,
258 // presumably a special font
260 tfont
*font_info::get_tfont(font_size fs
, int height
, int slant
, int fontno
)
262 if (last_tfont
== 0 || fs
!= last_size
263 || height
!= last_height
|| slant
!= last_slant
264 || global_ligature_mode
!= last_ligature_mode
265 || global_kern_mode
!= last_kern_mode
266 || fontno
!= number
) {
267 font_info
*f
= font_table
[fontno
];
268 tfont_spec
spec(f
->external_name
, f
->number
, f
->fm
, fs
, height
, slant
);
269 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
270 if (p
->fontno
== fontno
) {
272 spec
.bold_offset
= p
->offset
;
275 if (!spec
.is_bold
&& is_bold
) {
277 spec
.bold_offset
= bold_offset
;
279 spec
.track_kern
= track_kern
.compute(fs
.to_scaled_points());
280 spec
.ligature_mode
= global_ligature_mode
;
281 spec
.kern_mode
= global_kern_mode
;
282 switch (is_constant_spaced
) {
283 case CONSTANT_SPACE_NONE
:
285 case CONSTANT_SPACE_ABSOLUTE
:
286 spec
.is_constant_spaced
= 1;
287 spec
.constant_space_width
= constant_space
;
289 case CONSTANT_SPACE_RELATIVE
:
290 spec
.is_constant_spaced
= 1;
291 spec
.constant_space_width
292 = scale(constant_space
*fs
.to_scaled_points(),
299 if (fontno
!= number
)
300 return make_tfont(spec
);
301 last_tfont
= make_tfont(spec
);
303 last_height
= height
;
305 last_ligature_mode
= global_ligature_mode
;
306 last_kern_mode
= global_kern_mode
;
311 int font_info::get_bold(hunits
*res
)
321 void font_info::unbold()
329 void font_info::set_bold(hunits offset
)
331 if (!is_bold
|| offset
!= bold_offset
) {
333 bold_offset
= offset
;
338 void font_info::set_conditional_bold(int fontno
, hunits offset
)
340 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
341 if (p
->fontno
== fontno
) {
342 if (offset
!= p
->offset
) {
348 cond_bold_list
= new conditional_bold(fontno
, offset
, cond_bold_list
);
351 conditional_bold::conditional_bold(int f
, hunits h
, conditional_bold
*x
)
352 : next(x
), fontno(f
), offset(h
)
356 void font_info::conditional_unbold(int fontno
)
358 for (conditional_bold
**p
= &cond_bold_list
; *p
; p
= &(*p
)->next
)
359 if ((*p
)->fontno
== fontno
) {
360 conditional_bold
*tem
= *p
;
368 void font_info::set_constant_space(constant_space_type type
, units x
)
370 if (type
!= is_constant_spaced
371 || (type
!= CONSTANT_SPACE_NONE
&& x
!= constant_space
)) {
373 is_constant_spaced
= type
;
378 void font_info::set_track_kern(track_kerning_function
&tk
)
380 if (track_kern
!= tk
) {
386 void font_info::flush()
391 int font_info::is_named(symbol s
)
393 return internal_name
== s
;
396 symbol
font_info::get_name()
398 return internal_name
;
401 symbol
get_font_name(int fontno
, environment
*env
)
403 symbol f
= font_table
[fontno
]->get_name();
404 if (font_table
[fontno
]->is_style()) {
405 return concat(env
->get_family()->nm
, f
);
410 symbol
get_style_name(int fontno
)
412 if (font_table
[fontno
]->is_style())
413 return font_table
[fontno
]->get_name();
418 hunits
font_info::get_space_width(font_size fs
, int space_sz
)
420 if (is_constant_spaced
== CONSTANT_SPACE_NONE
)
421 return scale(hunits(fm
->get_space_width(fs
.to_scaled_points())),
423 else if (is_constant_spaced
== CONSTANT_SPACE_ABSOLUTE
)
424 return constant_space
;
426 return scale(constant_space
*fs
.to_scaled_points(),
427 units_per_inch
, 36*72*sizescale
);
430 hunits
font_info::get_narrow_space_width(font_size fs
)
432 charinfo
*ci
= get_charinfo(symbol("|"));
433 if (fm
->contains(ci
->get_index()))
434 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
436 return hunits(fs
.to_units()/6);
439 hunits
font_info::get_half_narrow_space_width(font_size fs
)
441 charinfo
*ci
= get_charinfo(symbol("^"));
442 if (fm
->contains(ci
->get_index()))
443 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
445 return hunits(fs
.to_units()/12);
450 tfont_spec::tfont_spec(symbol nm
, int n
, font
*f
,
451 font_size s
, int h
, int sl
)
452 : name(nm
), input_position(n
), fm(f
), size(s
),
453 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
456 if (height
== size
.to_scaled_points())
460 int tfont_spec::operator==(const tfont_spec
&spec
)
464 && input_position
== spec
.input_position
466 && height
== spec
.height
467 && slant
== spec
.slant
469 ? (spec
.is_bold
&& bold_offset
== spec
.bold_offset
)
471 && track_kern
== spec
.track_kern
472 && (is_constant_spaced
473 ? (spec
.is_constant_spaced
474 && constant_space_width
== spec
.constant_space_width
)
475 : !spec
.is_constant_spaced
)
476 && ligature_mode
== spec
.ligature_mode
477 && kern_mode
== spec
.kern_mode
)
483 tfont_spec
tfont_spec::plain()
485 return tfont_spec(name
, input_position
, fm
, size
, height
, slant
);
488 hunits
tfont::get_width(charinfo
*c
)
490 if (is_constant_spaced
)
491 return constant_space_width
;
493 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
494 + track_kern
+ bold_offset
);
496 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
500 vunits
tfont::get_char_height(charinfo
*c
)
502 vunits v
= fm
->get_height(c
->get_index(), size
.to_scaled_points());
503 if (height
!= 0 && height
!= size
.to_scaled_points())
504 return scale(v
, height
, size
.to_scaled_points());
509 vunits
tfont::get_char_depth(charinfo
*c
)
511 vunits v
= fm
->get_depth(c
->get_index(), size
.to_scaled_points());
512 if (height
!= 0 && height
!= size
.to_scaled_points())
513 return scale(v
, height
, size
.to_scaled_points());
518 hunits
tfont::get_char_skew(charinfo
*c
)
520 return hunits(fm
->get_skew(c
->get_index(), size
.to_scaled_points(), slant
));
523 hunits
tfont::get_italic_correction(charinfo
*c
)
525 return hunits(fm
->get_italic_correction(c
->get_index(), size
.to_scaled_points()));
528 hunits
tfont::get_left_italic_correction(charinfo
*c
)
530 return hunits(fm
->get_left_italic_correction(c
->get_index(),
531 size
.to_scaled_points()));
534 hunits
tfont::get_subscript_correction(charinfo
*c
)
536 return hunits(fm
->get_subscript_correction(c
->get_index(),
537 size
.to_scaled_points()));
540 inline int tfont::get_input_position()
542 return input_position
;
545 inline int tfont::contains(charinfo
*ci
)
547 return fm
->contains(ci
->get_index());
550 inline int tfont::get_character_type(charinfo
*ci
)
552 return fm
->get_character_type(ci
->get_index());
555 inline int tfont::get_bold(hunits
*res
)
565 inline int tfont::get_constant_space(hunits
*res
)
567 if (is_constant_spaced
) {
568 *res
= constant_space_width
;
575 inline hunits
tfont::get_track_kern()
580 inline tfont
*tfont::get_plain()
582 return plain_version
;
585 inline font_size
tfont::get_size()
590 inline symbol
tfont::get_name()
595 inline int tfont::get_height()
600 inline int tfont::get_slant()
605 symbol
SYMBOL_ff("ff");
606 symbol
SYMBOL_fi("fi");
607 symbol
SYMBOL_fl("fl");
608 symbol
SYMBOL_Fi("Fi");
609 symbol
SYMBOL_Fl("Fl");
611 charinfo
*tfont::get_lig(charinfo
*c1
, charinfo
*c2
)
613 if (ligature_mode
== 0)
616 if (c1
->get_ascii_code() == 'f') {
617 switch (c2
->get_ascii_code()) {
619 if (fm
->has_ligature(font::LIG_ff
))
620 ci
= get_charinfo(SYMBOL_ff
);
623 if (fm
->has_ligature(font::LIG_fi
))
624 ci
= get_charinfo(SYMBOL_fi
);
627 if (fm
->has_ligature(font::LIG_fl
))
628 ci
= get_charinfo(SYMBOL_fl
);
632 else if (ligature_mode
!= 2 && c1
->nm
== SYMBOL_ff
) {
633 switch (c2
->get_ascii_code()) {
635 if (fm
->has_ligature(font::LIG_ffi
))
636 ci
= get_charinfo(SYMBOL_Fi
);
639 if (fm
->has_ligature(font::LIG_ffl
))
640 ci
= get_charinfo(SYMBOL_Fl
);
644 if (ci
!= 0 && fm
->contains(ci
->get_index()))
649 inline int tfont::get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
)
654 int n
= fm
->get_kern(c1
->get_index(),
656 size
.to_scaled_points());
666 tfont
*tfont::tfont_list
= 0;
668 tfont::tfont(tfont_spec
&spec
) : tfont_spec(spec
)
672 tfont_spec plain_spec
= plain();
674 for (p
= tfont_list
; p
; p
= p
->next
)
675 if (*p
== plain_spec
) {
680 plain_version
= new tfont(plain_spec
);
685 class real_output_file
: public output_file
{
686 #ifndef POPEN_MISSING
689 int printing
; // decision via optional page list
690 int output_on
; // \O[0] or \O[1] escape calls
691 virtual void really_transparent_char(unsigned char) = 0;
692 virtual void really_print_line(hunits x
, vunits y
, node
*n
,
693 vunits before
, vunits after
, hunits width
) = 0;
694 virtual void really_begin_page(int pageno
, vunits page_length
) = 0;
695 virtual void really_copy_file(hunits x
, vunits y
, const char *filename
);
696 virtual void really_put_filename(const char *filename
);
697 virtual void really_on();
698 virtual void really_off();
704 void transparent_char(unsigned char);
705 void print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
706 void begin_page(int pageno
, vunits page_length
);
707 void put_filename(const char *filename
);
712 void copy_file(hunits x
, vunits y
, const char *filename
);
715 class suppress_output_file
: public real_output_file
{
717 suppress_output_file();
718 void really_transparent_char(unsigned char);
719 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
720 void really_begin_page(int pageno
, vunits page_length
);
723 class ascii_output_file
: public real_output_file
{
726 void really_transparent_char(unsigned char);
727 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
728 void really_begin_page(int pageno
, vunits page_length
);
729 void outc(unsigned char c
);
730 void outs(const char *s
);
733 void ascii_output_file::outc(unsigned char c
)
738 void ascii_output_file::outs(const char *s
)
748 class troff_output_file
: public real_output_file
{
757 tfont
*current_tfont
;
758 color
*current_fill_color
;
759 color
*current_glyph_color
;
760 int current_font_number
;
761 symbol
*font_position
;
763 enum { TBUF_SIZE
= 256 };
764 char tbuf
[TBUF_SIZE
];
772 void put(unsigned char c
);
774 void put(unsigned int i
);
775 void put(const char *s
);
776 void set_font(tfont
*tf
);
780 ~troff_output_file();
781 void trailer(vunits page_length
);
782 void put_char(charinfo
*, tfont
*, color
*, color
*);
783 void put_char_width(charinfo
*, tfont
*, color
*, color
*, hunits
, hunits
);
786 void moveto(hunits
, vunits
);
787 void start_special(tfont
*, color
*, color
*, int = 0);
788 void start_special();
789 void special_char(unsigned char c
);
792 void really_transparent_char(unsigned char c
);
793 void really_print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
794 void really_begin_page(int pageno
, vunits page_length
);
795 void really_copy_file(hunits x
, vunits y
, const char *filename
);
796 void really_put_filename(const char *filename
);
799 void draw(char, hvpair
*, int, font_size
, color
*, color
*);
800 void determine_line_limits (char code
, hvpair
*point
, int npoints
);
801 void check_charinfo(tfont
*tf
, charinfo
*ci
);
802 void glyph_color(color
*c
);
803 void fill_color(color
*c
);
804 int get_hpos() { return hpos
; }
805 int get_vpos() { return vpos
; }
806 void add_to_tag_list(string s
);
807 friend void space_char_hmotion_node::tprint(troff_output_file
*);
808 friend void unbreakable_space_node::tprint(troff_output_file
*);
811 static void put_string(const char *s
, FILE *fp
)
813 for (; *s
!= '\0'; ++s
)
817 inline void troff_output_file::put(char c
)
822 inline void troff_output_file::put(unsigned char c
)
827 inline void troff_output_file::put(const char *s
)
832 inline void troff_output_file::put(int i
)
834 put_string(i_to_a(i
), fp
);
837 inline void troff_output_file::put(unsigned int i
)
839 put_string(ui_to_a(i
), fp
);
842 void troff_output_file::start_special(tfont
*tf
, color
*gcol
, color
*fcol
,
854 void troff_output_file::start_special()
861 void troff_output_file::special_char(unsigned char c
)
868 void troff_output_file::end_special()
873 inline void troff_output_file::moveto(hunits h
, vunits v
)
879 void troff_output_file::really_print_line(hunits x
, vunits y
, node
*n
,
880 vunits before
, vunits after
, hunits
)
884 // Check whether we should push the current troff state and use
885 // the state at the start of the invocation of this diversion.
886 if (n
->div_nest_level
> cur_div_level
&& n
->push_state
) {
887 state
.push_state(n
->push_state
);
888 cur_div_level
= n
->div_nest_level
;
890 // Has the current diversion level decreased? Then we must pop the
892 while (n
->div_nest_level
< cur_div_level
) {
894 cur_div_level
= n
->div_nest_level
;
896 // Now check whether the state has changed.
897 if ((is_on() || n
->force_tprint())
898 && (state
.changed(n
->state
) || n
->is_tag() || n
->is_special
)) {
903 state
.flush(fp
, n
->state
, tag_list
);
904 tag_list
= string("");
911 // This ensures that transparent throughput will have a more predictable
917 put(before
.to_units());
919 put(after
.to_units());
923 inline void troff_output_file::word_marker()
930 inline void troff_output_file::right(hunits n
)
932 hpos
+= n
.to_units();
935 inline void troff_output_file::down(vunits n
)
937 vpos
+= n
.to_units();
940 void troff_output_file::do_motion()
951 if (hpos
!= output_hpos
) {
952 units n
= hpos
- output_hpos
;
953 if (n
> 0 && n
< hpos
) {
963 if (vpos
!= output_vpos
) {
964 units n
= vpos
- output_vpos
;
965 if (n
> 0 && n
< vpos
) {
981 void troff_output_file::flush_tbuf()
997 check_output_limits(hpos
, vpos
);
998 check_output_limits(hpos
, vpos
- current_size
);
1000 for (int i
= 0; i
< tbuf_len
; i
++)
1006 void troff_output_file::check_charinfo(tfont
*tf
, charinfo
*ci
)
1011 int height
= tf
->get_char_height(ci
).to_units();
1012 int width
= tf
->get_width(ci
).to_units()
1013 + tf
->get_italic_correction(ci
).to_units();
1014 int depth
= tf
->get_char_depth(ci
).to_units();
1015 check_output_limits(output_hpos
, output_vpos
- height
);
1016 check_output_limits(output_hpos
+ width
, output_vpos
+ depth
);
1019 void troff_output_file::put_char_width(charinfo
*ci
, tfont
*tf
,
1020 color
*gcol
, color
*fcol
,
1023 int kk
= k
.to_units();
1026 hpos
+= w
.to_units() + kk
;
1030 unsigned char c
= ci
->get_ascii_code();
1036 check_charinfo(tf
, ci
);
1037 if (ci
->numbered()) {
1039 put(ci
->get_number());
1043 const char *s
= ci
->nm
.contents();
1052 hpos
+= w
.to_units() + kk
;
1054 else if (tcommand_flag
) {
1055 if (tbuf_len
> 0 && hpos
== output_hpos
&& vpos
== output_vpos
1056 && (!gcol
|| gcol
== current_glyph_color
)
1057 && (!fcol
|| fcol
== current_fill_color
)
1059 && tbuf_len
< TBUF_SIZE
) {
1060 check_charinfo(tf
, ci
);
1061 tbuf
[tbuf_len
++] = c
;
1062 output_hpos
+= w
.to_units() + kk
;
1070 check_charinfo(tf
, ci
);
1071 tbuf
[tbuf_len
++] = c
;
1072 output_hpos
+= w
.to_units() + kk
;
1078 int n
= hpos
- output_hpos
;
1079 check_charinfo(tf
, ci
);
1080 // check_output_limits(output_hpos, output_vpos);
1081 if (vpos
== output_vpos
1082 && (!gcol
|| gcol
== current_glyph_color
)
1083 && (!fcol
|| fcol
== current_fill_color
)
1084 && n
> 0 && n
< 100 && !force_motion
) {
1085 put(char(n
/10 + '0'));
1086 put(char(n
%10 + '0'));
1097 hpos
+= w
.to_units() + kk
;
1101 void troff_output_file::put_char(charinfo
*ci
, tfont
*tf
,
1102 color
*gcol
, color
*fcol
)
1108 unsigned char c
= ci
->get_ascii_code();
1114 if (ci
->numbered()) {
1116 put(ci
->get_number());
1120 const char *s
= ci
->nm
.contents();
1131 int n
= hpos
- output_hpos
;
1132 if (vpos
== output_vpos
1133 && (!gcol
|| gcol
== current_glyph_color
)
1134 && (!fcol
|| fcol
== current_fill_color
)
1135 && n
> 0 && n
< 100) {
1136 put(char(n
/10 + '0'));
1137 put(char(n
%10 + '0'));
1152 // set_font calls `flush_tbuf' if necessary.
1154 void troff_output_file::set_font(tfont
*tf
)
1156 if (current_tfont
== tf
)
1159 int n
= tf
->get_input_position();
1160 symbol nm
= tf
->get_name();
1161 if (n
>= nfont_positions
|| font_position
[n
] != nm
) {
1167 if (n
>= nfont_positions
) {
1168 int old_nfont_positions
= nfont_positions
;
1169 symbol
*old_font_position
= font_position
;
1170 nfont_positions
*= 3;
1171 nfont_positions
/= 2;
1172 if (nfont_positions
<= n
)
1173 nfont_positions
= n
+ 10;
1174 font_position
= new symbol
[nfont_positions
];
1175 memcpy(font_position
, old_font_position
,
1176 old_nfont_positions
*sizeof(symbol
));
1177 a_delete old_font_position
;
1179 font_position
[n
] = nm
;
1181 if (current_font_number
!= n
) {
1185 current_font_number
= n
;
1187 int size
= tf
->get_size().to_scaled_points();
1188 if (current_size
!= size
) {
1192 current_size
= size
;
1194 int slant
= tf
->get_slant();
1195 if (current_slant
!= slant
) {
1199 current_slant
= slant
;
1201 int height
= tf
->get_height();
1202 if (current_height
!= height
) {
1204 put(height
== 0 ? current_size
: height
);
1206 current_height
= height
;
1211 // fill_color calls `flush_tbuf' and `do_motion' if necessary.
1213 void troff_output_file::fill_color(color
*col
)
1215 if (!col
|| current_fill_color
== col
)
1217 current_fill_color
= col
;
1223 unsigned int components
[4];
1225 cs
= col
->get_components(components
);
1264 // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1266 void troff_output_file::glyph_color(color
*col
)
1268 if (!col
|| current_glyph_color
== col
)
1270 current_glyph_color
= col
;
1274 // grotty doesn't like a color command if the vertical position is zero.
1277 unsigned int components
[4];
1279 cs
= col
->get_components(components
);
1318 void troff_output_file::add_to_tag_list(string s
)
1320 if (tag_list
== string(""))
1323 tag_list
+= string("\n");
1328 // determine_line_limits - works out the smallest box which will contain
1329 // the entity, code, built from the point array.
1330 void troff_output_file::determine_line_limits(char code
, hvpair
*point
,
1341 // only the h field is used when defining a circle
1342 check_output_limits(output_hpos
,
1343 output_vpos
- point
[0].h
.to_units()/2);
1344 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1345 output_vpos
+ point
[0].h
.to_units()/2);
1349 check_output_limits(output_hpos
,
1350 output_vpos
- point
[0].v
.to_units()/2);
1351 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1352 output_vpos
+ point
[0].v
.to_units()/2);
1358 check_output_limits(x
, y
);
1359 for (i
= 0; i
< npoints
; i
++) {
1360 x
+= point
[i
].h
.to_units();
1361 y
+= point
[i
].v
.to_units();
1362 check_output_limits(x
, y
);
1368 for (i
= 0; i
< npoints
; i
++) {
1369 x
+= point
[i
].h
.to_units();
1370 y
+= point
[i
].v
.to_units();
1371 check_output_limits(x
, y
);
1377 int minx
, miny
, maxx
, maxy
;
1380 p
[0] = point
[0].h
.to_units();
1381 p
[1] = point
[0].v
.to_units();
1382 p
[2] = point
[1].h
.to_units();
1383 p
[3] = point
[1].v
.to_units();
1384 if (adjust_arc_center(p
, c
)) {
1385 check_output_arc_limits(x
, y
,
1386 p
[0], p
[1], p
[2], p
[3],
1388 &minx
, &maxx
, &miny
, &maxy
);
1389 check_output_limits(minx
, miny
);
1390 check_output_limits(maxx
, maxy
);
1397 check_output_limits(x
, y
);
1398 for (i
= 0; i
< npoints
; i
++) {
1399 x
+= point
[i
].h
.to_units();
1400 y
+= point
[i
].v
.to_units();
1401 check_output_limits(x
, y
);
1407 for (i
= 0; i
< npoints
; i
++) {
1408 x
+= point
[i
].h
.to_units();
1409 y
+= point
[i
].v
.to_units();
1410 check_output_limits(x
, y
);
1415 void troff_output_file::draw(char code
, hvpair
*point
, int npoints
,
1416 font_size fsize
, color
*gcol
, color
*fcol
)
1424 int size
= fsize
.to_scaled_points();
1425 if (current_size
!= size
) {
1429 current_size
= size
;
1436 put(point
[0].h
.to_units());
1439 for (i
= 0; i
< npoints
; i
++) {
1441 put(point
[i
].h
.to_units());
1443 put(point
[i
].v
.to_units());
1445 determine_line_limits(code
, point
, npoints
);
1448 for (i
= 0; i
< npoints
; i
++)
1449 output_hpos
+= point
[i
].h
.to_units();
1452 for (i
= 0; i
< npoints
; i
++)
1453 output_vpos
+= point
[i
].v
.to_units();
1460 void troff_output_file::really_on()
1467 void troff_output_file::really_off()
1472 void troff_output_file::really_put_filename(const char *filename
)
1480 void troff_output_file::really_begin_page(int pageno
, vunits page_length
)
1484 if (page_length
> V0
) {
1486 put(page_length
.to_units());
1493 current_font_number
= -1;
1495 // current_height = 0;
1496 // current_slant = 0;
1502 for (int i
= 0; i
< nfont_positions
; i
++)
1503 font_position
[i
] = NULL_SYMBOL
;
1509 void troff_output_file::really_copy_file(hunits x
, vunits y
,
1510 const char *filename
)
1516 FILE *ifp
= include_search_path
.open_file_cautious(filename
);
1518 error("can't open `%1': %2", filename
, strerror(errno
));
1521 while ((c
= getc(ifp
)) != EOF
)
1528 current_font_number
= -1;
1529 for (int i
= 0; i
< nfont_positions
; i
++)
1530 font_position
[i
] = NULL_SYMBOL
;
1533 void troff_output_file::really_transparent_char(unsigned char c
)
1538 troff_output_file::~troff_output_file()
1540 a_delete font_position
;
1543 void troff_output_file::trailer(vunits page_length
)
1546 if (page_length
> V0
) {
1549 put(page_length
.to_units());
1555 troff_output_file::troff_output_file()
1556 : current_slant(0), current_height(0), current_fill_color(0),
1557 current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0),
1560 font_position
= new symbol
[nfont_positions
];
1565 put(units_per_inch
);
1576 output_file
*the_output
= 0;
1578 output_file::output_file()
1582 output_file::~output_file()
1586 void output_file::trailer(vunits
)
1590 void output_file::put_filename(const char *)
1594 void output_file::on()
1598 void output_file::off()
1602 real_output_file::real_output_file()
1603 : printing(0), output_on(1)
1605 #ifndef POPEN_MISSING
1607 if ((fp
= popen(pipe_command
, POPEN_WT
)) != 0) {
1611 error("pipe open failed: %1", strerror(errno
));
1614 #endif /* not POPEN_MISSING */
1618 real_output_file::~real_output_file()
1622 // To avoid looping, set fp to 0 before calling fatal().
1623 if (ferror(fp
) || fflush(fp
) < 0) {
1625 fatal("error writing output file");
1627 #ifndef POPEN_MISSING
1629 int result
= pclose(fp
);
1632 fatal("pclose failed");
1633 if (!WIFEXITED(result
))
1634 error("output process `%1' got fatal signal %2",
1636 WIFSIGNALED(result
) ? WTERMSIG(result
) : WSTOPSIG(result
));
1638 int exit_status
= WEXITSTATUS(result
);
1639 if (exit_status
!= 0)
1640 error("output process `%1' exited with status %2",
1641 pipe_command
, exit_status
);
1645 #endif /* not POPEN MISSING */
1646 if (fclose(fp
) < 0) {
1648 fatal("error closing output file");
1652 void real_output_file::flush()
1655 fatal("error writing output file");
1658 int real_output_file::is_printing()
1663 void real_output_file::begin_page(int pageno
, vunits page_length
)
1665 printing
= in_output_page_list(pageno
);
1667 really_begin_page(pageno
, page_length
);
1670 void real_output_file::copy_file(hunits x
, vunits y
, const char *filename
)
1672 if (printing
&& output_on
)
1673 really_copy_file(x
, y
, filename
);
1674 check_output_limits(x
.to_units(), y
.to_units());
1677 void real_output_file::transparent_char(unsigned char c
)
1679 if (printing
&& output_on
)
1680 really_transparent_char(c
);
1683 void real_output_file::print_line(hunits x
, vunits y
, node
*n
,
1684 vunits before
, vunits after
, hunits width
)
1687 really_print_line(x
, y
, n
, before
, after
, width
);
1688 delete_node_list(n
);
1691 void real_output_file::really_copy_file(hunits
, vunits
, const char *)
1696 void real_output_file::put_filename(const char *filename
)
1698 really_put_filename(filename
);
1701 void real_output_file::really_put_filename(const char *)
1705 void real_output_file::on()
1712 void real_output_file::off()
1718 int real_output_file::is_on()
1723 void real_output_file::really_on()
1727 void real_output_file::really_off()
1731 /* ascii_output_file */
1733 void ascii_output_file::really_transparent_char(unsigned char c
)
1738 void ascii_output_file::really_print_line(hunits
, vunits
, node
*n
,
1739 vunits
, vunits
, hunits
)
1742 n
->ascii_print(this);
1748 void ascii_output_file::really_begin_page(int /*pageno*/, vunits
/*page_length*/)
1750 fputs("<beginning of page>\n", fp
);
1753 ascii_output_file::ascii_output_file()
1757 /* suppress_output_file */
1759 suppress_output_file::suppress_output_file()
1763 void suppress_output_file::really_print_line(hunits
, vunits
, node
*, vunits
, vunits
, hunits
)
1767 void suppress_output_file::really_begin_page(int, vunits
)
1771 void suppress_output_file::really_transparent_char(unsigned char)
1775 /* glyphs, ligatures, kerns, discretionary breaks */
1777 class charinfo_node
: public node
{
1781 charinfo_node(charinfo
*, statem
*, int, node
* = 0);
1782 int ends_sentence();
1783 int overlaps_vertically();
1784 int overlaps_horizontally();
1787 charinfo_node::charinfo_node(charinfo
*c
, statem
*s
, int pop
, node
*x
)
1788 : node(x
, s
, pop
), ci(c
)
1792 int charinfo_node::ends_sentence()
1794 if (ci
->ends_sentence())
1796 else if (ci
->transparent())
1802 int charinfo_node::overlaps_horizontally()
1804 return ci
->overlaps_horizontally();
1807 int charinfo_node::overlaps_vertically()
1809 return ci
->overlaps_vertically();
1812 class glyph_node
: public charinfo_node
{
1813 static glyph_node
*free_list
;
1817 color
*fcol
; /* this is needed for grotty */
1820 glyph_node(charinfo
*, tfont
*, color
*, color
*, hunits
,
1821 statem
*, int, node
* = 0);
1824 void *operator new(size_t);
1825 void operator delete(void *);
1826 glyph_node(charinfo
*, tfont
*, color
*, color
*,
1827 statem
*, int, node
* = 0);
1830 node
*merge_glyph_node(glyph_node
*);
1831 node
*merge_self(node
*);
1833 node
*last_char_node();
1835 void vertical_extent(vunits
*, vunits
*);
1836 hunits
subscript_correction();
1837 hunits
italic_correction();
1838 hunits
left_italic_correction();
1840 hyphenation_type
get_hyphenation_type();
1842 color
*get_glyph_color();
1843 color
*get_fill_color();
1844 void tprint(troff_output_file
*);
1845 void zero_width_tprint(troff_output_file
*);
1846 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1847 node
*add_self(node
*, hyphen_list
**);
1848 void ascii_print(ascii_output_file
*);
1849 void asciify(macro
*);
1850 int character_type();
1858 glyph_node
*glyph_node::free_list
= 0;
1860 class ligature_node
: public glyph_node
{
1864 ligature_node(charinfo
*, tfont
*, color
*, color
*, hunits
,
1865 node
*, node
*, statem
*, int, node
* = 0);
1868 void *operator new(size_t);
1869 void operator delete(void *);
1870 ligature_node(charinfo
*, tfont
*, color
*, color
*,
1871 node
*, node
*, statem
*, int, node
* = 0);
1874 node
*add_self(node
*, hyphen_list
**);
1875 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1876 void ascii_print(ascii_output_file
*);
1877 void asciify(macro
*);
1884 class kern_pair_node
: public node
{
1889 kern_pair_node(hunits
, node
*, node
*, statem
*, int, node
* = 0);
1892 node
*merge_glyph_node(glyph_node
*);
1893 node
*add_self(node
*, hyphen_list
**);
1894 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1895 node
*add_discretionary_hyphen();
1897 node
*last_char_node();
1898 hunits
italic_correction();
1899 hunits
subscript_correction();
1900 void tprint(troff_output_file
*);
1901 hyphenation_type
get_hyphenation_type();
1902 int ends_sentence();
1903 void ascii_print(ascii_output_file
*);
1904 void asciify(macro
*);
1909 void vertical_extent(vunits
*, vunits
*);
1912 class dbreak_node
: public node
{
1917 dbreak_node(node
*, node
*, statem
*, int, node
* = 0);
1920 node
*merge_glyph_node(glyph_node
*);
1921 node
*add_discretionary_hyphen();
1923 node
*last_char_node();
1924 hunits
italic_correction();
1925 hunits
subscript_correction();
1926 void tprint(troff_output_file
*);
1927 breakpoint
*get_breakpoints(hunits width
, int ns
, breakpoint
*rest
= 0,
1930 int ends_sentence();
1931 void split(int, node
**, node
**);
1932 hyphenation_type
get_hyphenation_type();
1933 void ascii_print(ascii_output_file
*);
1934 void asciify(macro
*);
1941 void *glyph_node::operator new(size_t n
)
1943 assert(n
== sizeof(glyph_node
));
1945 const int BLOCK
= 1024;
1946 free_list
= (glyph_node
*)new char[sizeof(glyph_node
)*BLOCK
];
1947 for (int i
= 0; i
< BLOCK
- 1; i
++)
1948 free_list
[i
].next
= free_list
+ i
+ 1;
1949 free_list
[BLOCK
-1].next
= 0;
1951 glyph_node
*p
= free_list
;
1952 free_list
= (glyph_node
*)(free_list
->next
);
1957 void *ligature_node::operator new(size_t n
)
1962 void glyph_node::operator delete(void *p
)
1965 ((glyph_node
*)p
)->next
= free_list
;
1966 free_list
= (glyph_node
*)p
;
1970 void ligature_node::operator delete(void *p
)
1975 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
1976 statem
*s
, int pop
, node
*x
)
1977 : charinfo_node(c
, s
, pop
, x
), tf(t
), gcol(gc
), fcol(fc
)
1980 wid
= tf
->get_width(ci
);
1985 glyph_node::glyph_node(charinfo
*c
, tfont
*t
,
1986 color
*gc
, color
*fc
, hunits w
,
1987 statem
*s
, int pop
, node
*x
)
1988 : charinfo_node(c
, s
, pop
, x
), tf(t
), gcol(gc
), fcol(fc
), wid(w
)
1993 node
*glyph_node::copy()
1996 return new glyph_node(ci
, tf
, gcol
, fcol
, wid
, state
, div_nest_level
);
1998 return new glyph_node(ci
, tf
, gcol
, fcol
, state
, div_nest_level
);
2002 node
*glyph_node::merge_self(node
*nd
)
2004 return nd
->merge_glyph_node(this);
2007 int glyph_node::character_type()
2009 return tf
->get_character_type(ci
);
2012 node
*glyph_node::add_self(node
*n
, hyphen_list
**p
)
2014 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
2017 if (n
== 0 || (nn
= n
->merge_glyph_node(this)) == 0) {
2022 nn
= nn
->add_discretionary_hyphen();
2023 hyphen_list
*pp
= *p
;
2029 units
glyph_node::size()
2031 return tf
->get_size().to_units();
2034 hyphen_list
*glyph_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2037 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
2040 tfont
*node::get_tfont()
2045 tfont
*glyph_node::get_tfont()
2050 color
*node::get_glyph_color()
2055 color
*glyph_node::get_glyph_color()
2060 color
*node::get_fill_color()
2065 color
*glyph_node::get_fill_color()
2070 node
*node::merge_glyph_node(glyph_node
*)
2075 node
*glyph_node::merge_glyph_node(glyph_node
*gn
)
2077 if (tf
== gn
->tf
&& gcol
== gn
->gcol
&& fcol
== gn
->fcol
) {
2079 if ((lig
= tf
->get_lig(ci
, gn
->ci
)) != 0) {
2082 return new ligature_node(lig
, tf
, gcol
, fcol
, this, gn
, state
,
2083 gn
->div_nest_level
, next1
);
2086 if (tf
->get_kern(ci
, gn
->ci
, &kern
)) {
2089 return new kern_pair_node(kern
, this, gn
, state
,
2090 gn
->div_nest_level
, next1
);
2099 hunits
glyph_node::width()
2104 return tf
->get_width(ci
);
2108 node
*glyph_node::last_char_node()
2113 void glyph_node::vertical_extent(vunits
*min
, vunits
*max
)
2115 *min
= -tf
->get_char_height(ci
);
2116 *max
= tf
->get_char_depth(ci
);
2119 hunits
glyph_node::skew()
2121 return tf
->get_char_skew(ci
);
2124 hunits
glyph_node::subscript_correction()
2126 return tf
->get_subscript_correction(ci
);
2129 hunits
glyph_node::italic_correction()
2131 return tf
->get_italic_correction(ci
);
2134 hunits
glyph_node::left_italic_correction()
2136 return tf
->get_left_italic_correction(ci
);
2139 hyphenation_type
glyph_node::get_hyphenation_type()
2141 return HYPHEN_MIDDLE
;
2144 void glyph_node::ascii_print(ascii_output_file
*ascii
)
2146 unsigned char c
= ci
->get_ascii_code();
2150 ascii
->outs(ci
->nm
.contents());
2153 void glyph_node::debug_node()
2155 unsigned char c
= ci
->get_ascii_code();
2156 fprintf(stderr
, "{ %s [", type());
2158 fprintf(stderr
, "%c", c
);
2160 fprintf(stderr
, ci
->nm
.contents());
2162 fprintf(stderr
, " <push_state>");
2164 state
->display_state();
2165 fprintf(stderr
, " nest level %d", div_nest_level
);
2166 fprintf(stderr
, "]}\n");
2170 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2171 node
*gn1
, node
*gn2
, statem
*s
,
2173 : glyph_node(c
, t
, gc
, fc
, s
, pop
, x
), n1(gn1
), n2(gn2
)
2178 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2179 hunits w
, node
*gn1
, node
*gn2
, statem
*s
,
2181 : glyph_node(c
, t
, gc
, fc
, w
, s
, pop
, x
), n1(gn1
), n2(gn2
)
2186 ligature_node::~ligature_node()
2192 node
*ligature_node::copy()
2195 return new ligature_node(ci
, tf
, gcol
, fcol
, wid
, n1
->copy(), n2
->copy(),
2196 state
, div_nest_level
);
2198 return new ligature_node(ci
, tf
, gcol
, fcol
, n1
->copy(), n2
->copy(),
2199 state
, div_nest_level
);
2203 void ligature_node::ascii_print(ascii_output_file
*ascii
)
2205 n1
->ascii_print(ascii
);
2206 n2
->ascii_print(ascii
);
2209 hyphen_list
*ligature_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2211 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2212 return n1
->get_hyphen_list(hl
, count
);
2215 node
*ligature_node::add_self(node
*n
, hyphen_list
**p
)
2217 n
= n1
->add_self(n
, p
);
2218 n
= n2
->add_self(n
, p
);
2224 kern_pair_node::kern_pair_node(hunits n
, node
*first
, node
*second
,
2225 statem
* s
, int pop
, node
*x
)
2226 : node(x
, s
, pop
), amount(n
), n1(first
), n2(second
)
2230 dbreak_node::dbreak_node(node
*n
, node
*p
, statem
*s
, int pop
, node
*x
)
2231 : node(x
, s
, pop
), none(n
), pre(p
), post(0)
2235 node
*dbreak_node::merge_glyph_node(glyph_node
*gn
)
2237 glyph_node
*gn2
= (glyph_node
*)gn
->copy();
2238 node
*new_none
= none
? none
->merge_glyph_node(gn
) : 0;
2239 node
*new_post
= post
? post
->merge_glyph_node(gn2
) : 0;
2240 if (new_none
== 0 && new_post
== 0) {
2259 node
*kern_pair_node::merge_glyph_node(glyph_node
*gn
)
2261 node
*nd
= n2
->merge_glyph_node(gn
);
2265 nd
= n2
->merge_self(n1
);
2276 hunits
kern_pair_node::italic_correction()
2278 return n2
->italic_correction();
2281 hunits
kern_pair_node::subscript_correction()
2283 return n2
->subscript_correction();
2286 void kern_pair_node::vertical_extent(vunits
*min
, vunits
*max
)
2288 n1
->vertical_extent(min
, max
);
2290 n2
->vertical_extent(&min2
, &max2
);
2297 node
*kern_pair_node::add_discretionary_hyphen()
2299 tfont
*tf
= n2
->get_tfont();
2301 if (tf
->contains(soft_hyphen_char
)) {
2302 color
*gcol
= n2
->get_glyph_color();
2303 color
*fcol
= n2
->get_fill_color();
2307 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
,
2308 state
, div_nest_level
);
2309 node
*nn
= n
->merge_glyph_node(gn
);
2314 return new dbreak_node(this, nn
, state
, div_nest_level
, next1
);
2320 kern_pair_node::~kern_pair_node()
2328 dbreak_node::~dbreak_node()
2330 delete_node_list(pre
);
2331 delete_node_list(post
);
2332 delete_node_list(none
);
2335 node
*kern_pair_node::copy()
2337 return new kern_pair_node(amount
, n1
->copy(), n2
->copy(), state
,
2341 node
*copy_node_list(node
*n
)
2345 node
*nn
= n
->copy();
2359 void delete_node_list(node
*n
)
2368 node
*dbreak_node::copy()
2370 dbreak_node
*p
= new dbreak_node(copy_node_list(none
), copy_node_list(pre
),
2371 state
, div_nest_level
);
2372 p
->post
= copy_node_list(post
);
2376 hyphen_list
*node::get_hyphen_list(hyphen_list
*tail
, int *)
2381 hyphen_list
*kern_pair_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2383 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2384 return n1
->get_hyphen_list(hl
, count
);
2387 class hyphen_inhibitor_node
: public node
{
2389 hyphen_inhibitor_node(node
* = 0);
2395 hyphenation_type
get_hyphenation_type();
2398 hyphen_inhibitor_node::hyphen_inhibitor_node(node
*nd
) : node(nd
)
2402 node
*hyphen_inhibitor_node::copy()
2404 return new hyphen_inhibitor_node
;
2407 int hyphen_inhibitor_node::same(node
*)
2412 const char *hyphen_inhibitor_node::type()
2414 return "hyphen_inhibitor_node";
2417 int hyphen_inhibitor_node::force_tprint()
2422 int hyphen_inhibitor_node::is_tag()
2427 hyphenation_type
hyphen_inhibitor_node::get_hyphenation_type()
2429 return HYPHEN_INHIBIT
;
2432 /* add_discretionary_hyphen methods */
2434 node
*dbreak_node::add_discretionary_hyphen()
2437 post
= post
->add_discretionary_hyphen();
2439 none
= none
->add_discretionary_hyphen();
2443 node
*node::add_discretionary_hyphen()
2445 tfont
*tf
= get_tfont();
2447 return new hyphen_inhibitor_node(this);
2448 if (tf
->contains(soft_hyphen_char
)) {
2449 color
*gcol
= get_glyph_color();
2450 color
*fcol
= get_fill_color();
2454 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
,
2455 state
, div_nest_level
);
2456 node
*n1
= n
->merge_glyph_node(gn
);
2461 return new dbreak_node(this, n1
, state
, div_nest_level
, next1
);
2466 node
*node::merge_self(node
*)
2471 node
*node::add_self(node
*n
, hyphen_list
** /*p*/)
2477 node
*kern_pair_node::add_self(node
*n
, hyphen_list
**p
)
2479 n
= n1
->add_self(n
, p
);
2480 n
= n2
->add_self(n
, p
);
2486 hunits
node::width()
2491 node
*node::last_char_node()
2496 int node::force_tprint()
2506 hunits
hmotion_node::width()
2513 return points_to_units(10);
2516 void node::debug_node()
2518 fprintf(stderr
, "{ %s ", type());
2520 fprintf(stderr
, " <push_state>");
2522 fprintf(stderr
, " <state>");
2523 fprintf(stderr
, " nest level %d", div_nest_level
);
2524 fprintf(stderr
, " }\n");
2528 void node::debug_node_list()
2539 hunits
kern_pair_node::width()
2541 return n1
->width() + n2
->width() + amount
;
2544 node
*kern_pair_node::last_char_node()
2546 node
*nd
= n2
->last_char_node();
2549 return n1
->last_char_node();
2552 hunits
dbreak_node::width()
2555 for (node
*n
= none
; n
!= 0; n
= n
->next
)
2560 node
*dbreak_node::last_char_node()
2562 for (node
*n
= none
; n
; n
= n
->next
) {
2563 node
*last_node
= n
->last_char_node();
2570 hunits
dbreak_node::italic_correction()
2572 return none
? none
->italic_correction() : H0
;
2575 hunits
dbreak_node::subscript_correction()
2577 return none
? none
->subscript_correction() : H0
;
2580 class italic_corrected_node
: public node
{
2584 italic_corrected_node(node
*, hunits
, statem
*, int, node
* = 0);
2585 ~italic_corrected_node();
2587 void ascii_print(ascii_output_file
*);
2588 void asciify(macro
*);
2590 node
*last_char_node();
2591 void vertical_extent(vunits
*, vunits
*);
2592 int ends_sentence();
2593 int overlaps_horizontally();
2594 int overlaps_vertically();
2596 hyphenation_type
get_hyphenation_type();
2598 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2599 int character_type();
2600 void tprint(troff_output_file
*);
2601 hunits
subscript_correction();
2603 node
*add_self(node
*, hyphen_list
**);
2609 node
*node::add_italic_correction(hunits
*wd
)
2611 hunits ic
= italic_correction();
2618 return new italic_corrected_node(this, ic
, state
, div_nest_level
, next1
);
2622 italic_corrected_node::italic_corrected_node(node
*nn
, hunits xx
, statem
*s
,
2624 : node(p
, s
, pop
), n(nn
), x(xx
)
2629 italic_corrected_node::~italic_corrected_node()
2634 node
*italic_corrected_node::copy()
2636 return new italic_corrected_node(n
->copy(), x
, state
, div_nest_level
);
2639 hunits
italic_corrected_node::width()
2641 return n
->width() + x
;
2644 void italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
2646 n
->vertical_extent(min
, max
);
2649 void italic_corrected_node::tprint(troff_output_file
*out
)
2655 hunits
italic_corrected_node::skew()
2657 return n
->skew() - x
/2;
2660 hunits
italic_corrected_node::subscript_correction()
2662 return n
->subscript_correction() - x
;
2665 void italic_corrected_node::ascii_print(ascii_output_file
*out
)
2667 n
->ascii_print(out
);
2670 int italic_corrected_node::ends_sentence()
2672 return n
->ends_sentence();
2675 int italic_corrected_node::overlaps_horizontally()
2677 return n
->overlaps_horizontally();
2680 int italic_corrected_node::overlaps_vertically()
2682 return n
->overlaps_vertically();
2685 node
*italic_corrected_node::last_char_node()
2687 return n
->last_char_node();
2690 tfont
*italic_corrected_node::get_tfont()
2692 return n
->get_tfont();
2695 hyphenation_type
italic_corrected_node::get_hyphenation_type()
2697 return n
->get_hyphenation_type();
2700 node
*italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
2702 nd
= n
->add_self(nd
, p
);
2703 hunits not_interested
;
2704 nd
= nd
->add_italic_correction(¬_interested
);
2710 hyphen_list
*italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
2713 return n
->get_hyphen_list(tail
, count
);
2716 int italic_corrected_node::character_type()
2718 return n
->character_type();
2721 class break_char_node
: public node
{
2726 break_char_node(node
*, int, color
*, node
* = 0);
2727 break_char_node(node
*, int, color
*, statem
*, int, node
* = 0);
2731 vunits
vertical_width();
2732 node
*last_char_node();
2733 int character_type();
2734 int ends_sentence();
2735 node
*add_self(node
*, hyphen_list
**);
2736 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2737 void tprint(troff_output_file
*);
2738 void zero_width_tprint(troff_output_file
*);
2739 void ascii_print(ascii_output_file
*);
2740 void asciify(macro
*);
2741 hyphenation_type
get_hyphenation_type();
2742 int overlaps_vertically();
2743 int overlaps_horizontally();
2752 break_char_node::break_char_node(node
*n
, int bc
, color
*c
, node
*x
)
2753 : node(x
), ch(n
), break_code(bc
), col(c
)
2757 break_char_node::break_char_node(node
*n
, int bc
, color
*c
, statem
*s
,
2759 : node(x
, s
, pop
), ch(n
), break_code(bc
), col(c
)
2763 break_char_node::~break_char_node()
2768 node
*break_char_node::copy()
2770 return new break_char_node(ch
->copy(), break_code
, col
, state
,
2774 hunits
break_char_node::width()
2779 vunits
break_char_node::vertical_width()
2781 return ch
->vertical_width();
2784 node
*break_char_node::last_char_node()
2786 return ch
->last_char_node();
2789 int break_char_node::character_type()
2791 return ch
->character_type();
2794 int break_char_node::ends_sentence()
2796 return ch
->ends_sentence();
2799 node
*break_char_node::add_self(node
*n
, hyphen_list
**p
)
2801 assert((*p
)->hyphenation_code
== 0);
2802 if ((*p
)->breakable
&& (break_code
& 1)) {
2803 n
= new space_node(H0
, col
, n
);
2808 if ((*p
)->breakable
&& (break_code
& 2)) {
2809 n
= new space_node(H0
, col
, n
);
2812 hyphen_list
*pp
= *p
;
2818 hyphen_list
*break_char_node::get_hyphen_list(hyphen_list
*tail
, int *)
2820 return new hyphen_list(0, tail
);
2823 hyphenation_type
break_char_node::get_hyphenation_type()
2825 return HYPHEN_MIDDLE
;
2828 void break_char_node::ascii_print(ascii_output_file
*ascii
)
2830 ch
->ascii_print(ascii
);
2833 int break_char_node::overlaps_vertically()
2835 return ch
->overlaps_vertically();
2838 int break_char_node::overlaps_horizontally()
2840 return ch
->overlaps_horizontally();
2843 units
break_char_node::size()
2848 tfont
*break_char_node::get_tfont()
2850 return ch
->get_tfont();
2853 node
*extra_size_node::copy()
2855 return new extra_size_node(n
, state
, div_nest_level
);
2858 extra_size_node::extra_size_node(vunits i
, statem
*s
, int pop
)
2859 : node(0, s
, pop
), n(i
)
2863 extra_size_node::extra_size_node(vunits i
)
2868 node
*vertical_size_node::copy()
2870 return new vertical_size_node(n
, state
, div_nest_level
);
2873 vertical_size_node::vertical_size_node(vunits i
, statem
*s
, int pop
)
2874 : node(0, s
, pop
), n(i
)
2878 vertical_size_node::vertical_size_node(vunits i
)
2883 node
*hmotion_node::copy()
2885 return new hmotion_node(n
, was_tab
, unformat
, col
, state
, div_nest_level
);
2888 node
*space_char_hmotion_node::copy()
2890 return new space_char_hmotion_node(n
, col
, state
, div_nest_level
);
2893 vmotion_node::vmotion_node(vunits i
, color
*c
)
2898 vmotion_node::vmotion_node(vunits i
, color
*c
, statem
*s
, int pop
)
2899 : node(0, s
, pop
), n(i
), col(c
)
2903 node
*vmotion_node::copy()
2905 return new vmotion_node(n
, col
, state
, div_nest_level
);
2908 node
*dummy_node::copy()
2910 return new dummy_node
;
2913 node
*transparent_dummy_node::copy()
2915 return new transparent_dummy_node
;
2918 hline_node::~hline_node()
2924 hline_node::hline_node(hunits i
, node
*c
, node
*nxt
)
2925 : node(nxt
), x(i
), n(c
)
2929 hline_node::hline_node(hunits i
, node
*c
, statem
*s
, int pop
, node
*nxt
)
2930 : node(nxt
, s
, pop
), x(i
), n(c
)
2934 node
*hline_node::copy()
2936 return new hline_node(x
, n
? n
->copy() : 0, state
, div_nest_level
);
2939 hunits
hline_node::width()
2941 return x
< H0
? H0
: x
;
2944 vline_node::vline_node(vunits i
, node
*c
, node
*nxt
)
2945 : node(nxt
), x(i
), n(c
)
2949 vline_node::vline_node(vunits i
, node
*c
, statem
*s
, int pop
, node
*nxt
)
2950 : node(nxt
, s
, pop
), x(i
), n(c
)
2954 vline_node::~vline_node()
2960 node
*vline_node::copy()
2962 return new vline_node(x
, n
? n
->copy() : 0, state
, div_nest_level
);
2965 hunits
vline_node::width()
2967 return n
== 0 ? H0
: n
->width();
2970 zero_width_node::zero_width_node(node
*nd
, statem
*s
, int pop
)
2971 : node(0, s
, pop
), n(nd
)
2975 zero_width_node::zero_width_node(node
*nd
)
2980 zero_width_node::~zero_width_node()
2982 delete_node_list(n
);
2985 node
*zero_width_node::copy()
2987 return new zero_width_node(copy_node_list(n
), state
, div_nest_level
);
2990 int node_list_character_type(node
*p
)
2993 for (; p
; p
= p
->next
)
2994 t
|= p
->character_type();
2998 int zero_width_node::character_type()
3000 return node_list_character_type(n
);
3003 void node_list_vertical_extent(node
*p
, vunits
*min
, vunits
*max
)
3007 vunits cur_vpos
= V0
;
3009 for (; p
; p
= p
->next
) {
3010 p
->vertical_extent(&v1
, &v2
);
3017 cur_vpos
+= p
->vertical_width();
3021 void zero_width_node::vertical_extent(vunits
*min
, vunits
*max
)
3023 node_list_vertical_extent(n
, min
, max
);
3026 overstrike_node::overstrike_node()
3027 : list(0), max_width(H0
)
3031 overstrike_node::overstrike_node(statem
*s
, int pop
)
3032 : node(0, s
, pop
), list(0), max_width(H0
)
3036 overstrike_node::~overstrike_node()
3038 delete_node_list(list
);
3041 node
*overstrike_node::copy()
3043 overstrike_node
*on
= new overstrike_node(state
, div_nest_level
);
3044 for (node
*tem
= list
; tem
; tem
= tem
->next
)
3045 on
->overstrike(tem
->copy());
3049 void overstrike_node::overstrike(node
*n
)
3053 hunits w
= n
->width();
3057 for (p
= &list
; *p
; p
= &(*p
)->next
)
3063 hunits
overstrike_node::width()
3068 bracket_node::bracket_node()
3069 : list(0), max_width(H0
)
3073 bracket_node::bracket_node(statem
*s
, int pop
)
3074 : node(0, s
, pop
), list(0), max_width(H0
)
3078 bracket_node::~bracket_node()
3080 delete_node_list(list
);
3083 node
*bracket_node::copy()
3085 bracket_node
*on
= new bracket_node(state
, div_nest_level
);
3086 node
*last_node
= 0;
3090 for (tem
= list
; tem
; tem
= tem
->next
) {
3092 tem
->next
->last
= tem
;
3095 for (tem
= last_node
; tem
; tem
= tem
->last
)
3096 on
->bracket(tem
->copy());
3100 void bracket_node::bracket(node
*n
)
3104 hunits w
= n
->width();
3111 hunits
bracket_node::width()
3121 int node::merge_space(hunits
, hunits
, hunits
)
3127 space_node
*space_node::free_list
= 0;
3129 void *space_node::operator new(size_t n
)
3131 assert(n
== sizeof(space_node
));
3133 free_list
= (space_node
*)new char[sizeof(space_node
)*BLOCK
];
3134 for (int i
= 0; i
< BLOCK
- 1; i
++)
3135 free_list
[i
].next
= free_list
+ i
+ 1;
3136 free_list
[BLOCK
-1].next
= 0;
3138 space_node
*p
= free_list
;
3139 free_list
= (space_node
*)(free_list
->next
);
3144 inline void space_node::operator delete(void *p
)
3147 ((space_node
*)p
)->next
= free_list
;
3148 free_list
= (space_node
*)p
;
3153 space_node::space_node(hunits nn
, color
*c
, node
*p
)
3154 : node(p
, 0, 0), n(nn
), set(0), was_escape_colon(0), col(c
)
3158 space_node::space_node(hunits nn
, color
*c
, statem
*s
, int pop
, node
*p
)
3159 : node(p
, s
, pop
), n(nn
), set(0), was_escape_colon(0), col(c
)
3163 space_node::space_node(hunits nn
, int s
, int flag
, color
*c
, statem
*st
,
3165 : node(p
, st
, pop
), n(nn
), set(s
), was_escape_colon(flag
), col(c
)
3170 space_node::~space_node()
3175 node
*space_node::copy()
3177 return new space_node(n
, set
, was_escape_colon
, col
, state
, div_nest_level
);
3180 int space_node::force_tprint()
3185 int space_node::is_tag()
3190 int space_node::nspaces()
3195 int space_node::merge_space(hunits h
, hunits
, hunits
)
3201 hunits
space_node::width()
3206 void node::spread_space(int*, hunits
*)
3210 void space_node::spread_space(int *n_spaces
, hunits
*desired_space
)
3213 assert(*n_spaces
> 0);
3214 if (*n_spaces
== 1) {
3215 n
+= *desired_space
;
3216 *desired_space
= H0
;
3219 hunits extra
= *desired_space
/ *n_spaces
;
3220 *desired_space
-= extra
;
3228 void node::freeze_space()
3232 void space_node::freeze_space()
3237 void node::is_escape_colon()
3241 void space_node::is_escape_colon()
3243 was_escape_colon
= 1;
3246 diverted_space_node::diverted_space_node(vunits d
, statem
*s
, int pop
,
3248 : node(p
, s
, pop
), n(d
)
3252 diverted_space_node::diverted_space_node(vunits d
, node
*p
)
3257 node
*diverted_space_node::copy()
3259 return new diverted_space_node(n
, state
, div_nest_level
);
3262 diverted_copy_file_node::diverted_copy_file_node(symbol s
, statem
*st
,
3264 : node(p
, st
, pop
), filename(s
)
3268 diverted_copy_file_node::diverted_copy_file_node(symbol s
, node
*p
)
3269 : node(p
), filename(s
)
3273 node
*diverted_copy_file_node::copy()
3275 return new diverted_copy_file_node(filename
, state
, div_nest_level
);
3278 int node::ends_sentence()
3283 int kern_pair_node::ends_sentence()
3285 switch (n2
->ends_sentence()) {
3295 return n1
->ends_sentence();
3298 int node_list_ends_sentence(node
*n
)
3300 for (; n
!= 0; n
= n
->next
)
3301 switch (n
->ends_sentence()) {
3314 int dbreak_node::ends_sentence()
3316 return node_list_ends_sentence(none
);
3319 int node::overlaps_horizontally()
3324 int node::overlaps_vertically()
3329 int node::discardable()
3334 int space_node::discardable()
3339 vunits
node::vertical_width()
3344 vunits
vline_node::vertical_width()
3349 vunits
vmotion_node::vertical_width()
3354 int node::set_unformat_flag()
3359 int node::character_type()
3364 hunits
node::subscript_correction()
3369 hunits
node::italic_correction()
3374 hunits
node::left_italic_correction()
3384 /* vertical_extent methods */
3386 void node::vertical_extent(vunits
*min
, vunits
*max
)
3388 vunits v
= vertical_width();
3399 void vline_node::vertical_extent(vunits
*min
, vunits
*max
)
3402 node::vertical_extent(min
, max
);
3405 n
->vertical_extent(&cmin
, &cmax
);
3406 vunits h
= n
->size();
3413 // we print the first character and then move up, so
3415 // we print the last character and then move up h
3428 // we move down by h and then print the first character, so
3438 /* ascii_print methods */
3440 static void ascii_print_reverse_node_list(ascii_output_file
*ascii
, node
*n
)
3444 ascii_print_reverse_node_list(ascii
, n
->next
);
3445 n
->ascii_print(ascii
);
3448 void dbreak_node::ascii_print(ascii_output_file
*ascii
)
3450 ascii_print_reverse_node_list(ascii
, none
);
3453 void kern_pair_node::ascii_print(ascii_output_file
*ascii
)
3455 n1
->ascii_print(ascii
);
3456 n2
->ascii_print(ascii
);
3459 void node::ascii_print(ascii_output_file
*)
3463 void space_node::ascii_print(ascii_output_file
*ascii
)
3469 void hmotion_node::ascii_print(ascii_output_file
*ascii
)
3471 // this is pretty arbitrary
3472 if (n
>= points_to_units(2))
3476 void space_char_hmotion_node::ascii_print(ascii_output_file
*ascii
)
3481 /* asciify methods */
3483 void node::asciify(macro
*m
)
3488 void glyph_node::asciify(macro
*m
)
3490 unsigned char c
= ci
->get_asciify_code();
3492 c
= ci
->get_ascii_code();
3501 void kern_pair_node::asciify(macro
*m
)
3509 static void asciify_reverse_node_list(macro
*m
, node
*n
)
3513 asciify_reverse_node_list(m
, n
->next
);
3517 void dbreak_node::asciify(macro
*m
)
3519 asciify_reverse_node_list(m
, none
);
3524 void ligature_node::asciify(macro
*m
)
3532 void break_char_node::asciify(macro
*m
)
3539 void italic_corrected_node::asciify(macro
*m
)
3546 void left_italic_corrected_node::asciify(macro
*m
)
3555 void hmotion_node::asciify(macro
*m
)
3565 space_char_hmotion_node::space_char_hmotion_node(hunits i
, color
*c
,
3568 : hmotion_node(i
, c
, s
, pop
, nxt
)
3572 space_char_hmotion_node::space_char_hmotion_node(hunits i
, color
*c
,
3574 : hmotion_node(i
, c
, 0, 0, nxt
)
3578 void space_char_hmotion_node::asciify(macro
*m
)
3580 m
->append(ESCAPE_SPACE
);
3584 void space_node::asciify(macro
*m
)
3586 if (was_escape_colon
) {
3587 m
->append(ESCAPE_COLON
);
3594 void word_space_node::asciify(macro
*m
)
3596 for (width_list
*w
= orig_width
; w
; w
= w
->next
)
3601 void unbreakable_space_node::asciify(macro
*m
)
3603 m
->append(ESCAPE_TILDE
);
3607 void line_start_node::asciify(macro
*)
3612 void vertical_size_node::asciify(macro
*)
3617 breakpoint
*node::get_breakpoints(hunits
/*width*/, int /*nspaces*/,
3618 breakpoint
*rest
, int /*is_inner*/)
3628 breakpoint
*space_node::get_breakpoints(hunits wd
, int ns
,
3629 breakpoint
*rest
, int is_inner
)
3631 if (next
&& next
->discardable())
3633 breakpoint
*bp
= new breakpoint
;
3640 bp
->index
= rest
->index
+ 1;
3650 int space_node::nbreaks()
3652 if (next
&& next
->discardable())
3658 static breakpoint
*node_list_get_breakpoints(node
*p
, hunits
*widthp
,
3659 int ns
, breakpoint
*rest
)
3662 rest
= p
->get_breakpoints(*widthp
,
3664 node_list_get_breakpoints(p
->next
, widthp
, ns
,
3667 *widthp
+= p
->width();
3672 breakpoint
*dbreak_node::get_breakpoints(hunits wd
, int ns
,
3673 breakpoint
*rest
, int is_inner
)
3675 breakpoint
*bp
= new breakpoint
;
3678 for (node
*tem
= pre
; tem
!= 0; tem
= tem
->next
)
3679 bp
->width
+= tem
->width();
3684 bp
->index
= rest
->index
+ 1;
3691 return node_list_get_breakpoints(none
, &wd
, ns
, bp
);
3694 int dbreak_node::nbreaks()
3697 for (node
*tem
= none
; tem
!= 0; tem
= tem
->next
)
3698 i
+= tem
->nbreaks();
3702 void node::split(int /*where*/, node
** /*prep*/, node
** /*postp*/)
3707 void space_node::split(int where
, node
**pre
, node
**post
)
3715 static void node_list_split(node
*p
, int *wherep
, node
**prep
, node
**postp
)
3719 int nb
= p
->nbreaks();
3720 node_list_split(p
->next
, wherep
, prep
, postp
);
3725 else if (*wherep
< nb
) {
3727 p
->split(*wherep
, prep
, postp
);
3736 void dbreak_node::split(int where
, node
**prep
, node
**postp
)
3746 for (tem
= pre
; tem
->next
!= 0; tem
= tem
->next
)
3757 node_list_split(none
, &where
, prep
, postp
);
3763 hyphenation_type
node::get_hyphenation_type()
3765 return HYPHEN_BOUNDARY
;
3768 hyphenation_type
dbreak_node::get_hyphenation_type()
3770 return HYPHEN_INHIBIT
;
3773 hyphenation_type
kern_pair_node::get_hyphenation_type()
3775 return HYPHEN_MIDDLE
;
3778 hyphenation_type
dummy_node::get_hyphenation_type()
3780 return HYPHEN_MIDDLE
;
3783 hyphenation_type
transparent_dummy_node::get_hyphenation_type()
3785 return HYPHEN_MIDDLE
;
3788 hyphenation_type
hmotion_node::get_hyphenation_type()
3790 return HYPHEN_MIDDLE
;
3793 hyphenation_type
space_char_hmotion_node::get_hyphenation_type()
3795 return HYPHEN_MIDDLE
;
3798 hyphenation_type
overstrike_node::get_hyphenation_type()
3800 return HYPHEN_MIDDLE
;
3803 hyphenation_type
space_node::get_hyphenation_type()
3805 if (was_escape_colon
)
3806 return HYPHEN_MIDDLE
;
3807 return HYPHEN_BOUNDARY
;
3810 hyphenation_type
unbreakable_space_node::get_hyphenation_type()
3812 return HYPHEN_MIDDLE
;
3815 int node::interpret(macro
*)
3820 special_node::special_node(const macro
&m
, int n
)
3821 : mac(m
), no_init_string(n
)
3823 font_size fs
= curenv
->get_font_size();
3824 int char_height
= curenv
->get_char_height();
3825 int char_slant
= curenv
->get_char_slant();
3826 int fontno
= env_definite_font(curenv
);
3827 tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fontno
);
3828 if (curenv
->is_composite())
3829 tf
= tf
->get_plain();
3830 gcol
= curenv
->get_glyph_color();
3831 fcol
= curenv
->get_fill_color();
3835 special_node::special_node(const macro
&m
, tfont
*t
,
3836 color
*gc
, color
*fc
,
3839 : node(0, s
, pop
), mac(m
), tf(t
), gcol(gc
), fcol(fc
), no_init_string(n
)
3844 int special_node::same(node
*n
)
3846 return mac
== ((special_node
*)n
)->mac
3847 && tf
== ((special_node
*)n
)->tf
3848 && gcol
== ((special_node
*)n
)->gcol
3849 && fcol
== ((special_node
*)n
)->fcol
3850 && no_init_string
== ((special_node
*)n
)->no_init_string
;
3853 const char *special_node::type()
3855 return "special_node";
3858 int special_node::ends_sentence()
3863 int special_node::force_tprint()
3868 int special_node::is_tag()
3873 node
*special_node::copy()
3875 return new special_node(mac
, tf
, gcol
, fcol
, state
, div_nest_level
,
3879 void special_node::tprint_start(troff_output_file
*out
)
3881 out
->start_special(tf
, gcol
, fcol
, no_init_string
);
3884 void special_node::tprint_char(troff_output_file
*out
, unsigned char c
)
3886 out
->special_char(c
);
3889 void special_node::tprint_end(troff_output_file
*out
)
3894 tfont
*special_node::get_tfont()
3901 suppress_node::suppress_node(int on_or_off
, int issue_limits
)
3902 : is_on(on_or_off
), emit_limits(issue_limits
), filename(0), position(0),
3907 suppress_node::suppress_node(symbol f
, char p
, int id
)
3908 : is_on(2), emit_limits(0), filename(f
), position(p
), image_id(id
)
3913 suppress_node::suppress_node(int issue_limits
, int on_or_off
,
3914 symbol f
, char p
, int id
,
3916 : node(0, s
, pop
), is_on(on_or_off
), emit_limits(issue_limits
), filename(f
),
3917 position(p
), image_id(id
)
3921 int suppress_node::same(node
*n
)
3923 return ((is_on
== ((suppress_node
*)n
)->is_on
)
3924 && (emit_limits
== ((suppress_node
*)n
)->emit_limits
)
3925 && (filename
== ((suppress_node
*)n
)->filename
)
3926 && (position
== ((suppress_node
*)n
)->position
)
3927 && (image_id
== ((suppress_node
*)n
)->image_id
));
3930 const char *suppress_node::type()
3932 return "suppress_node";
3935 node
*suppress_node::copy()
3937 return new suppress_node(emit_limits
, is_on
, filename
, position
, image_id
,
3938 state
, div_nest_level
);
3943 tag_node::tag_node()
3949 tag_node::tag_node(string s
, int delay
)
3950 : tag_string(s
), delayed(delay
)
3952 is_special
= !delay
;
3955 tag_node::tag_node(string s
, statem
*st
, int pop
, int delay
)
3956 : node(0, st
, pop
), tag_string(s
), delayed(delay
)
3958 is_special
= !delay
;
3961 node
*tag_node::copy()
3963 return new tag_node(tag_string
, state
, div_nest_level
, delayed
);
3966 void tag_node::tprint(troff_output_file
*out
)
3969 out
->add_to_tag_list(tag_string
);
3971 out
->state
.add_tag(out
->fp
, tag_string
);
3974 int tag_node::same(node
*nd
)
3976 return tag_string
== ((tag_node
*)nd
)->tag_string
3977 && delayed
== ((tag_node
*)nd
)->delayed
;
3980 const char *tag_node::type()
3985 int tag_node::force_tprint()
3990 int tag_node::is_tag()
3995 int tag_node::ends_sentence()
4000 int get_reg_int(const char *p
)
4002 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
4004 if (r
&& (r
->get_value(&prev_value
)))
4005 return (int)prev_value
;
4007 warning(WARN_REG
, "number register `%1' not defined", p
);
4011 const char *get_reg_str(const char *p
)
4013 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
4015 return r
->get_string();
4017 warning(WARN_REG
, "register `%1' not defined", p
);
4021 void suppress_node::put(troff_output_file
*out
, const char *s
)
4024 while (s
[i
] != (char)0) {
4025 out
->special_char(s
[i
]);
4031 * We need to remember the start of the image and its name.
4034 static char last_position
= 0;
4035 static const char *last_image_filename
= 0;
4036 static int last_image_id
= 0;
4038 inline int min(int a
, int b
)
4040 return a
< b
? a
: b
;
4044 * tprint - if (is_on == 2)
4045 * remember current position (l, r, c, i) and filename
4051 * emit postscript bounds for image
4053 * if (suppress boolean differs from current state)
4056 * record current page
4057 * set low water mark.
4060 void suppress_node::tprint(troff_output_file
*out
)
4062 int current_page
= topdiv
->get_page_number();
4063 // firstly check to see whether this suppress node contains
4064 // an image filename & position.
4066 // remember position and filename
4067 last_position
= position
;
4068 char *tem
= (char *)last_image_filename
;
4069 last_image_filename
= strsave(filename
.contents());
4072 last_image_id
= image_id
;
4073 // printf("start of image and page = %d\n", current_page);
4076 // now check whether the suppress node requires us to issue limits.
4079 // remember that the filename will contain a %d in which the
4080 // last_image_id is placed
4081 if (last_image_filename
== (char *) 0)
4084 sprintf(name
, last_image_filename
, last_image_id
);
4086 switch (last_position
) {
4088 out
->start_special();
4089 put(out
, "devtag:.centered-image");
4092 out
->start_special();
4093 put(out
, "devtag:.right-image");
4096 out
->start_special();
4097 put(out
, "devtag:.left-image");
4105 out
->start_special();
4106 put(out
, "devtag:.auto-image ");
4111 // postscript (or other device)
4112 if (suppress_start_page
> 0 && current_page
!= suppress_start_page
)
4113 error("suppression limit registers span more than one page;\n"
4114 "image description %1 will be wrong", image_no
);
4115 // if (topdiv->get_page_number() != suppress_start_page)
4116 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
4117 // topdiv->get_page_number(), suppress_start_page);
4119 // remember that the filename will contain a %d in which the
4120 // image_no is placed
4122 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
4123 topdiv
->get_page_number(),
4124 get_reg_int("opminx"), get_reg_int("opminy"),
4125 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
4126 // page offset + line length
4127 get_reg_int(".o") + get_reg_int(".l"),
4128 name
, hresolution
, vresolution
, get_reg_str(".F"));
4135 // lastly we reset the output registers
4136 reset_output_registers();
4140 suppress_start_page
= current_page
;
4145 int suppress_node::force_tprint()
4150 int suppress_node::is_tag()
4155 hunits
suppress_node::width()
4160 /* composite_node */
4162 class composite_node
: public charinfo_node
{
4166 composite_node(node
*, charinfo
*, tfont
*, statem
*, int, node
* = 0);
4170 node
*last_char_node();
4172 void tprint(troff_output_file
*);
4173 hyphenation_type
get_hyphenation_type();
4174 void ascii_print(ascii_output_file
*);
4175 void asciify(macro
*);
4176 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
4177 node
*add_self(node
*, hyphen_list
**);
4183 void vertical_extent(vunits
*, vunits
*);
4184 vunits
vertical_width();
4187 composite_node::composite_node(node
*p
, charinfo
*c
, tfont
*t
, statem
*s
,
4189 : charinfo_node(c
, s
, pop
, x
), n(p
), tf(t
)
4193 composite_node::~composite_node()
4195 delete_node_list(n
);
4198 node
*composite_node::copy()
4200 return new composite_node(copy_node_list(n
), ci
, tf
, state
, div_nest_level
);
4203 hunits
composite_node::width()
4206 if (tf
->get_constant_space(&x
))
4209 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4212 if (tf
->get_bold(&offset
))
4214 x
+= tf
->get_track_kern();
4218 node
*composite_node::last_char_node()
4223 vunits
composite_node::vertical_width()
4226 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4227 v
+= tem
->vertical_width();
4231 units
composite_node::size()
4233 return tf
->get_size().to_units();
4236 hyphenation_type
composite_node::get_hyphenation_type()
4238 return HYPHEN_MIDDLE
;
4241 void composite_node::asciify(macro
*m
)
4243 unsigned char c
= ci
->get_asciify_code();
4245 c
= ci
->get_ascii_code();
4254 void composite_node::ascii_print(ascii_output_file
*ascii
)
4256 unsigned char c
= ci
->get_ascii_code();
4260 ascii
->outs(ci
->nm
.contents());
4264 hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
4267 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
4270 node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
4272 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
4276 nn
= nn
->add_discretionary_hyphen();
4277 hyphen_list
*pp
= *p
;
4283 tfont
*composite_node::get_tfont()
4288 node
*reverse_node_list(node
*n
)
4300 void composite_node::vertical_extent(vunits
*minimum
, vunits
*maximum
)
4302 n
= reverse_node_list(n
);
4303 node_list_vertical_extent(n
, minimum
, maximum
);
4304 n
= reverse_node_list(n
);
4307 width_list::width_list(hunits w
, hunits s
)
4308 : width(w
), sentence_width(s
), next(0)
4312 width_list::width_list(width_list
*w
)
4313 : width(w
->width
), sentence_width(w
->sentence_width
), next(0)
4317 word_space_node::word_space_node(hunits d
, color
*c
, width_list
*w
, node
*x
)
4318 : space_node(d
, c
, x
), orig_width(w
), unformat(0)
4322 word_space_node::word_space_node(hunits d
, int s
, color
*c
, width_list
*w
,
4323 int flag
, statem
*st
, int pop
, node
*x
)
4324 : space_node(d
, s
, 0, c
, st
, pop
, x
), orig_width(w
), unformat(flag
)
4328 word_space_node::~word_space_node()
4330 width_list
*w
= orig_width
;
4332 width_list
*tmp
= w
;
4338 node
*word_space_node::copy()
4340 assert(orig_width
!= 0);
4341 width_list
*w_old_curr
= orig_width
;
4342 width_list
*w_new_curr
= new width_list(w_old_curr
);
4343 width_list
*w_new
= w_new_curr
;
4344 w_old_curr
= w_old_curr
->next
;
4345 while (w_old_curr
!= 0) {
4346 w_new_curr
->next
= new width_list(w_old_curr
);
4347 w_new_curr
= w_new_curr
->next
;
4348 w_old_curr
= w_old_curr
->next
;
4350 return new word_space_node(n
, set
, col
, w_new
, unformat
, state
,
4354 int word_space_node::set_unformat_flag()
4360 void word_space_node::tprint(troff_output_file
*out
)
4362 out
->fill_color(col
);
4367 int word_space_node::merge_space(hunits h
, hunits sw
, hunits ssw
)
4370 assert(orig_width
!= 0);
4371 width_list
*w
= orig_width
;
4372 for (; w
->next
; w
= w
->next
)
4374 w
->next
= new width_list(sw
, ssw
);
4378 unbreakable_space_node::unbreakable_space_node(hunits d
, color
*c
, node
*x
)
4379 : word_space_node(d
, c
, 0, x
)
4383 unbreakable_space_node::unbreakable_space_node(hunits d
, int s
,
4384 color
*c
, statem
*st
, int pop
,
4386 : word_space_node(d
, s
, c
, 0, 0, st
, pop
, x
)
4390 node
*unbreakable_space_node::copy()
4392 return new unbreakable_space_node(n
, set
, col
, state
, div_nest_level
);
4395 int unbreakable_space_node::force_tprint()
4400 int unbreakable_space_node::is_tag()
4405 breakpoint
*unbreakable_space_node::get_breakpoints(hunits
, int,
4406 breakpoint
*rest
, int)
4411 int unbreakable_space_node::nbreaks()
4416 void unbreakable_space_node::split(int, node
**, node
**)
4421 int unbreakable_space_node::merge_space(hunits
, hunits
, hunits
)
4430 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4431 color
*gc
, color
*fc
)
4432 : npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4434 point
= new hvpair
[npoints
];
4435 for (int i
= 0; i
< npoints
; i
++)
4439 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4440 color
*gc
, color
*fc
, statem
*st
, int pop
)
4441 : node(0, st
, pop
), npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4443 point
= new hvpair
[npoints
];
4444 for (int i
= 0; i
< npoints
; i
++)
4448 int draw_node::same(node
*n
)
4450 draw_node
*nd
= (draw_node
*)n
;
4451 if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
4452 || gcol
!= nd
->gcol
|| fcol
!= nd
->fcol
)
4454 for (int i
= 0; i
< npoints
; i
++)
4455 if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
4460 const char *draw_node::type()
4465 int draw_node::force_tprint()
4470 int draw_node::is_tag()
4475 draw_node::~draw_node()
4481 hunits
draw_node::width()
4484 for (int i
= 0; i
< npoints
; i
++)
4489 vunits
draw_node::vertical_width()
4494 for (int i
= 0; i
< npoints
; i
++)
4499 node
*draw_node::copy()
4501 return new draw_node(code
, point
, npoints
, sz
, gcol
, fcol
, state
,
4505 void draw_node::tprint(troff_output_file
*out
)
4507 out
->draw(code
, point
, npoints
, sz
, gcol
, fcol
);
4510 /* tprint methods */
4512 void glyph_node::tprint(troff_output_file
*out
)
4514 tfont
*ptf
= tf
->get_plain();
4516 out
->put_char_width(ci
, ptf
, gcol
, fcol
, width(), H0
);
4519 int bold
= tf
->get_bold(&offset
);
4520 hunits w
= ptf
->get_width(ci
);
4523 int cs
= tf
->get_constant_space(&x
);
4533 k
= tf
->get_track_kern();
4535 out
->put_char(ci
, ptf
, gcol
, fcol
);
4538 out
->put_char_width(ci
, ptf
, gcol
, fcol
, w
, k
);
4542 void glyph_node::zero_width_tprint(troff_output_file
*out
)
4544 tfont
*ptf
= tf
->get_plain();
4546 int bold
= tf
->get_bold(&offset
);
4548 int cs
= tf
->get_constant_space(&x
);
4550 x
-= ptf
->get_width(ci
);
4556 out
->put_char(ci
, ptf
, gcol
, fcol
);
4559 out
->put_char(ci
, ptf
, gcol
, fcol
);
4560 out
->right(-offset
);
4566 void break_char_node::tprint(troff_output_file
*t
)
4571 void break_char_node::zero_width_tprint(troff_output_file
*t
)
4573 ch
->zero_width_tprint(t
);
4576 void hline_node::tprint(troff_output_file
*out
)
4586 hunits w
= n
->width();
4588 error("horizontal line drawing character must have positive width");
4599 out
->right(xx
- xx2
);
4602 hunits rem
= x
- w
*i
;
4604 if (n
->overlaps_horizontally()) {
4607 out
->right(rem
- w
);
4617 void vline_node::tprint(troff_output_file
*out
)
4623 vunits h
= n
->size();
4624 int overlaps
= n
->overlaps_vertically();
4629 vunits rem
= y
- i
*h
;
4631 out
->right(n
->width());
4636 n
->zero_width_tprint(out
);
4640 n
->zero_width_tprint(out
);
4649 out
->down(-h
- rem
);
4655 vunits rem
= y
- i
*h
;
4658 out
->right(n
->width());
4663 n
->zero_width_tprint(out
);
4666 n
->zero_width_tprint(out
);
4675 void zero_width_node::tprint(troff_output_file
*out
)
4680 n
->zero_width_tprint(out
);
4683 int hpos
= out
->get_hpos();
4684 int vpos
= out
->get_vpos();
4690 out
->moveto(hpos
, vpos
);
4693 void overstrike_node::tprint(troff_output_file
*out
)
4696 for (node
*tem
= list
; tem
; tem
= tem
->next
) {
4697 hunits x
= (max_width
- tem
->width())/2;
4698 out
->right(x
- pos
);
4700 tem
->zero_width_tprint(out
);
4702 out
->right(max_width
- pos
);
4705 void bracket_node::tprint(troff_output_file
*out
)
4711 for (tem
= list
; tem
; tem
= tem
->next
)
4713 vunits h
= list
->size();
4714 vunits totalh
= h
*npieces
;
4715 vunits y
= (totalh
- h
)/2;
4717 for (tem
= list
; tem
; tem
= tem
->next
) {
4718 tem
->zero_width_tprint(out
);
4721 out
->right(max_width
);
4722 out
->down(totalh
- y
);
4725 void node::tprint(troff_output_file
*)
4729 void node::zero_width_tprint(troff_output_file
*out
)
4731 int hpos
= out
->get_hpos();
4732 int vpos
= out
->get_vpos();
4734 out
->moveto(hpos
, vpos
);
4737 void space_node::tprint(troff_output_file
*out
)
4739 out
->fill_color(col
);
4743 void hmotion_node::tprint(troff_output_file
*out
)
4745 out
->fill_color(col
);
4749 void space_char_hmotion_node::tprint(troff_output_file
*out
)
4751 out
->fill_color(col
);
4753 // we emit the space width as a negative glyph index
4757 out
->put(-n
.to_units());
4763 void vmotion_node::tprint(troff_output_file
*out
)
4765 out
->fill_color(col
);
4769 void kern_pair_node::tprint(troff_output_file
*out
)
4776 static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
4780 tprint_reverse_node_list(out
, n
->next
);
4784 void dbreak_node::tprint(troff_output_file
*out
)
4786 tprint_reverse_node_list(out
, none
);
4789 void composite_node::tprint(troff_output_file
*out
)
4792 int is_bold
= tf
->get_bold(&bold_offset
);
4793 hunits track_kern
= tf
->get_track_kern();
4794 hunits constant_space
;
4795 int is_constant_spaced
= tf
->get_constant_space(&constant_space
);
4797 if (is_constant_spaced
) {
4799 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4808 int hpos
= out
->get_hpos();
4809 int vpos
= out
->get_vpos();
4810 tprint_reverse_node_list(out
, n
);
4811 out
->moveto(hpos
, vpos
);
4812 out
->right(bold_offset
);
4814 tprint_reverse_node_list(out
, n
);
4815 if (is_constant_spaced
)
4818 out
->right(track_kern
);
4821 node
*make_composite_node(charinfo
*s
, environment
*env
)
4823 int fontno
= env_definite_font(env
);
4825 error("no current font");
4828 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4829 node
*n
= charinfo_to_node_list(s
, env
);
4830 font_size fs
= env
->get_font_size();
4831 int char_height
= env
->get_char_height();
4832 int char_slant
= env
->get_char_slant();
4833 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
,
4835 if (env
->is_composite())
4836 tf
= tf
->get_plain();
4837 return new composite_node(n
, s
, tf
, 0, 0, 0);
4840 node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
4842 int fontno
= env_definite_font(env
);
4844 error("no current font");
4847 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4849 int found
= font_table
[fontno
]->contains(s
);
4851 macro
*mac
= s
->get_macro();
4852 if (mac
&& s
->is_fallback())
4853 return make_composite_node(s
, env
);
4854 if (s
->numbered()) {
4855 if (!no_error_message
)
4856 warning(WARN_CHAR
, "can't find numbered character %1",
4860 special_font_list
*sf
= font_table
[fontno
]->sf
;
4861 while (sf
!= 0 && !found
) {
4864 found
= font_table
[fn
]->contains(s
);
4868 symbol f
= font_table
[fontno
]->get_name();
4869 string
gl(f
.contents());
4871 gl
+= s
->nm
.contents();
4873 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
4874 if (ci
&& ci
->get_macro())
4875 return make_composite_node(ci
, env
);
4878 sf
= global_special_fonts
;
4879 while (sf
!= 0 && !found
) {
4882 found
= font_table
[fn
]->contains(s
);
4887 if (mac
&& s
->is_special())
4888 return make_composite_node(s
, env
);
4890 for (fn
= 0; fn
< font_table_size
; fn
++)
4892 && font_table
[fn
]->is_special()
4893 && font_table
[fn
]->contains(s
)) {
4899 if (!no_error_message
&& s
->first_time_not_found()) {
4900 unsigned char input_code
= s
->get_ascii_code();
4901 if (input_code
!= 0) {
4902 if (csgraph(input_code
))
4903 warning(WARN_CHAR
, "can't find character `%1'", input_code
);
4905 warning(WARN_CHAR
, "can't find character with input code %1",
4908 else if (s
->nm
.contents())
4909 warning(WARN_CHAR
, "can't find special character `%1'",
4915 font_size fs
= env
->get_font_size();
4916 int char_height
= env
->get_char_height();
4917 int char_slant
= env
->get_char_slant();
4918 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
4919 if (env
->is_composite())
4920 tf
= tf
->get_plain();
4921 color
*gcol
= env
->get_glyph_color();
4922 color
*fcol
= env
->get_fill_color();
4923 return new glyph_node(s
, tf
, gcol
, fcol
, 0, 0);
4926 node
*make_node(charinfo
*ci
, environment
*env
)
4928 switch (ci
->get_special_translation()) {
4929 case charinfo::TRANSLATE_SPACE
:
4930 return new space_char_hmotion_node(env
->get_space_width(),
4931 env
->get_fill_color());
4932 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4933 return new unbreakable_space_node(env
->get_space_width(),
4934 env
->get_fill_color());
4935 case charinfo::TRANSLATE_DUMMY
:
4936 return new dummy_node
;
4937 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4938 error("translation to \\% ignored in this context");
4941 charinfo
*tem
= ci
->get_translation();
4944 macro
*mac
= ci
->get_macro();
4945 if (mac
&& ci
->is_normal())
4946 return make_composite_node(ci
, env
);
4948 return make_glyph_node(ci
, env
);
4951 int character_exists(charinfo
*ci
, environment
*env
)
4953 if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
4955 charinfo
*tem
= ci
->get_translation();
4958 if (ci
->get_macro())
4960 node
*nd
= make_glyph_node(ci
, env
, 1);
4968 node
*node::add_char(charinfo
*ci
, environment
*env
,
4969 hunits
*widthp
, int *spacep
, node
**glyph_comp_np
)
4972 switch (ci
->get_special_translation()) {
4973 case charinfo::TRANSLATE_SPACE
:
4974 res
= new space_char_hmotion_node(env
->get_space_width(),
4975 env
->get_fill_color(), this);
4976 *widthp
+= res
->width();
4978 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4979 res
= new unbreakable_space_node(env
->get_space_width(),
4980 env
->get_fill_color(), this);
4981 res
->freeze_space();
4982 *widthp
+= res
->width();
4983 *spacep
+= res
->nspaces();
4985 case charinfo::TRANSLATE_DUMMY
:
4986 return new dummy_node(this);
4987 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4988 return add_discretionary_hyphen();
4990 charinfo
*tem
= ci
->get_translation();
4993 macro
*mac
= ci
->get_macro();
4994 if (mac
&& ci
->is_normal()) {
4995 res
= make_composite_node(ci
, env
);
4998 *widthp
+= res
->width();
5000 *glyph_comp_np
= res
;
5004 *glyph_comp_np
= res
;
5009 node
*gn
= make_glyph_node(ci
, env
);
5013 hunits old_width
= width();
5014 node
*p
= gn
->merge_self(this);
5016 *widthp
+= gn
->width();
5021 *widthp
+= p
->width() - old_width
;
5025 *glyph_comp_np
= res
;
5029 if (ci
->can_break_before())
5031 if (ci
->can_break_after())
5034 node
*next1
= res
->next
;
5036 res
= new break_char_node(res
, break_code
, env
->get_fill_color(), next1
);
5044 int same_node(node
*n1
, node
*n2
)
5048 return n1
->type() == n2
->type() && n1
->same(n2
);
5056 int same_node_list(node
*n1
, node
*n2
)
5059 if (n1
->type() != n2
->type() || !n1
->same(n2
))
5067 int extra_size_node::same(node
*nd
)
5069 return n
== ((extra_size_node
*)nd
)->n
;
5072 const char *extra_size_node::type()
5074 return "extra_size_node";
5077 int extra_size_node::force_tprint()
5082 int extra_size_node::is_tag()
5087 int vertical_size_node::same(node
*nd
)
5089 return n
== ((vertical_size_node
*)nd
)->n
;
5092 const char *vertical_size_node::type()
5094 return "vertical_size_node";
5097 int vertical_size_node::set_unformat_flag()
5102 int vertical_size_node::force_tprint()
5107 int vertical_size_node::is_tag()
5112 int hmotion_node::same(node
*nd
)
5114 return n
== ((hmotion_node
*)nd
)->n
5115 && col
== ((hmotion_node
*)nd
)->col
;
5118 const char *hmotion_node::type()
5120 return "hmotion_node";
5123 int hmotion_node::set_unformat_flag()
5129 int hmotion_node::force_tprint()
5134 int hmotion_node::is_tag()
5139 node
*hmotion_node::add_self(node
*nd
, hyphen_list
**p
)
5142 hyphen_list
*pp
= *p
;
5148 hyphen_list
*hmotion_node::get_hyphen_list(hyphen_list
*tail
, int *)
5150 return new hyphen_list(0, tail
);
5153 int space_char_hmotion_node::same(node
*nd
)
5155 return n
== ((space_char_hmotion_node
*)nd
)->n
5156 && col
== ((space_char_hmotion_node
*)nd
)->col
;
5159 const char *space_char_hmotion_node::type()
5161 return "space_char_hmotion_node";
5164 int space_char_hmotion_node::force_tprint()
5169 int space_char_hmotion_node::is_tag()
5174 node
*space_char_hmotion_node::add_self(node
*nd
, hyphen_list
**p
)
5177 hyphen_list
*pp
= *p
;
5183 hyphen_list
*space_char_hmotion_node::get_hyphen_list(hyphen_list
*tail
,
5186 return new hyphen_list(0, tail
);
5189 int vmotion_node::same(node
*nd
)
5191 return n
== ((vmotion_node
*)nd
)->n
5192 && col
== ((vmotion_node
*)nd
)->col
;
5195 const char *vmotion_node::type()
5197 return "vmotion_node";
5200 int vmotion_node::force_tprint()
5205 int vmotion_node::is_tag()
5210 int hline_node::same(node
*nd
)
5212 return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
5215 const char *hline_node::type()
5217 return "hline_node";
5220 int hline_node::force_tprint()
5225 int hline_node::is_tag()
5230 int vline_node::same(node
*nd
)
5232 return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
5235 const char *vline_node::type()
5237 return "vline_node";
5240 int vline_node::force_tprint()
5245 int vline_node::is_tag()
5250 int dummy_node::same(node
* /*nd*/)
5255 const char *dummy_node::type()
5257 return "dummy_node";
5260 int dummy_node::force_tprint()
5265 int dummy_node::is_tag()
5270 int transparent_dummy_node::same(node
* /*nd*/)
5275 const char *transparent_dummy_node::type()
5277 return "transparent_dummy_node";
5280 int transparent_dummy_node::force_tprint()
5285 int transparent_dummy_node::is_tag()
5290 int transparent_dummy_node::ends_sentence()
5295 int zero_width_node::same(node
*nd
)
5297 return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
5300 const char *zero_width_node::type()
5302 return "zero_width_node";
5305 int zero_width_node::force_tprint()
5310 int zero_width_node::is_tag()
5315 int italic_corrected_node::same(node
*nd
)
5317 return (x
== ((italic_corrected_node
*)nd
)->x
5318 && same_node(n
, ((italic_corrected_node
*)nd
)->n
));
5321 const char *italic_corrected_node::type()
5323 return "italic_corrected_node";
5326 int italic_corrected_node::force_tprint()
5331 int italic_corrected_node::is_tag()
5336 left_italic_corrected_node::left_italic_corrected_node(node
*xx
)
5341 left_italic_corrected_node::left_italic_corrected_node(statem
*s
, int pop
,
5343 : node(xx
, s
, pop
), n(0)
5347 left_italic_corrected_node::~left_italic_corrected_node()
5352 node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
5355 hunits lic
= gn
->left_italic_correction();
5356 if (!lic
.is_zero()) {
5363 node
*nd
= n
->merge_glyph_node(gn
);
5366 x
= n
->left_italic_correction();
5373 node
*left_italic_corrected_node::copy()
5375 left_italic_corrected_node
*nd
=
5376 new left_italic_corrected_node(state
, div_nest_level
);
5384 void left_italic_corrected_node::tprint(troff_output_file
*out
)
5392 const char *left_italic_corrected_node::type()
5394 return "left_italic_corrected_node";
5397 int left_italic_corrected_node::force_tprint()
5402 int left_italic_corrected_node::is_tag()
5407 int left_italic_corrected_node::same(node
*nd
)
5409 return (x
== ((left_italic_corrected_node
*)nd
)->x
5410 && same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
5413 void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
5416 n
->ascii_print(out
);
5419 hunits
left_italic_corrected_node::width()
5421 return n
? n
->width() + x
: H0
;
5424 void left_italic_corrected_node::vertical_extent(vunits
*minimum
,
5428 n
->vertical_extent(minimum
, maximum
);
5430 node::vertical_extent(minimum
, maximum
);
5433 hunits
left_italic_corrected_node::skew()
5435 return n
? n
->skew() + x
/2 : H0
;
5438 hunits
left_italic_corrected_node::subscript_correction()
5440 return n
? n
->subscript_correction() : H0
;
5443 hunits
left_italic_corrected_node::italic_correction()
5445 return n
? n
->italic_correction() : H0
;
5448 int left_italic_corrected_node::ends_sentence()
5450 return n
? n
->ends_sentence() : 0;
5453 int left_italic_corrected_node::overlaps_horizontally()
5455 return n
? n
->overlaps_horizontally() : 0;
5458 int left_italic_corrected_node::overlaps_vertically()
5460 return n
? n
->overlaps_vertically() : 0;
5463 node
*left_italic_corrected_node::last_char_node()
5465 return n
? n
->last_char_node() : 0;
5468 tfont
*left_italic_corrected_node::get_tfont()
5470 return n
? n
->get_tfont() : 0;
5473 hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
5476 return n
->get_hyphenation_type();
5478 return HYPHEN_MIDDLE
;
5481 hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
5484 return n
? n
->get_hyphen_list(tail
, count
) : tail
;
5487 node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
5490 nd
= new left_italic_corrected_node(state
, div_nest_level
, nd
);
5491 nd
= n
->add_self(nd
, p
);
5498 int left_italic_corrected_node::character_type()
5500 return n
? n
->character_type() : 0;
5503 int overstrike_node::same(node
*nd
)
5505 return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
5508 const char *overstrike_node::type()
5510 return "overstrike_node";
5513 int overstrike_node::force_tprint()
5518 int overstrike_node::is_tag()
5523 node
*overstrike_node::add_self(node
*n
, hyphen_list
**p
)
5526 hyphen_list
*pp
= *p
;
5532 hyphen_list
*overstrike_node::get_hyphen_list(hyphen_list
*tail
, int *)
5534 return new hyphen_list(0, tail
);
5537 int bracket_node::same(node
*nd
)
5539 return same_node_list(list
, ((bracket_node
*)nd
)->list
);
5542 const char *bracket_node::type()
5544 return "bracket_node";
5547 int bracket_node::force_tprint()
5552 int bracket_node::is_tag()
5557 int composite_node::same(node
*nd
)
5559 return ci
== ((composite_node
*)nd
)->ci
5560 && same_node_list(n
, ((composite_node
*)nd
)->n
);
5563 const char *composite_node::type()
5565 return "composite_node";
5568 int composite_node::force_tprint()
5573 int composite_node::is_tag()
5578 int glyph_node::same(node
*nd
)
5580 return ci
== ((glyph_node
*)nd
)->ci
5581 && tf
== ((glyph_node
*)nd
)->tf
5582 && gcol
== ((glyph_node
*)nd
)->gcol
5583 && fcol
== ((glyph_node
*)nd
)->fcol
;
5586 const char *glyph_node::type()
5588 return "glyph_node";
5591 int glyph_node::force_tprint()
5596 int glyph_node::is_tag()
5601 int ligature_node::same(node
*nd
)
5603 return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
5604 && same_node(n2
, ((ligature_node
*)nd
)->n2
)
5605 && glyph_node::same(nd
));
5608 const char *ligature_node::type()
5610 return "ligature_node";
5613 int ligature_node::force_tprint()
5618 int ligature_node::is_tag()
5623 int kern_pair_node::same(node
*nd
)
5625 return (amount
== ((kern_pair_node
*)nd
)->amount
5626 && same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
5627 && same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
5630 const char *kern_pair_node::type()
5632 return "kern_pair_node";
5635 int kern_pair_node::force_tprint()
5640 int kern_pair_node::is_tag()
5645 int dbreak_node::same(node
*nd
)
5647 return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
5648 && same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
5649 && same_node_list(post
, ((dbreak_node
*)nd
)->post
));
5652 const char *dbreak_node::type()
5654 return "dbreak_node";
5657 int dbreak_node::force_tprint()
5662 int dbreak_node::is_tag()
5667 int break_char_node::same(node
*nd
)
5669 return break_code
== ((break_char_node
*)nd
)->break_code
5670 && col
== ((break_char_node
*)nd
)->col
5671 && same_node(ch
, ((break_char_node
*)nd
)->ch
);
5674 const char *break_char_node::type()
5676 return "break_char_node";
5679 int break_char_node::force_tprint()
5684 int break_char_node::is_tag()
5689 int line_start_node::same(node
* /*nd*/)
5694 const char *line_start_node::type()
5696 return "line_start_node";
5699 int line_start_node::force_tprint()
5704 int line_start_node::is_tag()
5709 int space_node::same(node
*nd
)
5711 return n
== ((space_node
*)nd
)->n
5712 && set
== ((space_node
*)nd
)->set
5713 && col
== ((space_node
*)nd
)->col
;
5716 const char *space_node::type()
5718 return "space_node";
5721 int word_space_node::same(node
*nd
)
5723 return n
== ((word_space_node
*)nd
)->n
5724 && set
== ((word_space_node
*)nd
)->set
5725 && col
== ((word_space_node
*)nd
)->col
;
5728 const char *word_space_node::type()
5730 return "word_space_node";
5733 int word_space_node::force_tprint()
5738 int word_space_node::is_tag()
5743 void unbreakable_space_node::tprint(troff_output_file
*out
)
5745 out
->fill_color(col
);
5747 // we emit the space width as a negative glyph index
5751 out
->put(-n
.to_units());
5757 int unbreakable_space_node::same(node
*nd
)
5759 return n
== ((unbreakable_space_node
*)nd
)->n
5760 && set
== ((unbreakable_space_node
*)nd
)->set
5761 && col
== ((unbreakable_space_node
*)nd
)->col
;
5764 const char *unbreakable_space_node::type()
5766 return "unbreakable_space_node";
5769 node
*unbreakable_space_node::add_self(node
*nd
, hyphen_list
**p
)
5772 hyphen_list
*pp
= *p
;
5778 hyphen_list
*unbreakable_space_node::get_hyphen_list(hyphen_list
*tail
, int *)
5780 return new hyphen_list(0, tail
);
5783 int diverted_space_node::same(node
*nd
)
5785 return n
== ((diverted_space_node
*)nd
)->n
;
5788 const char *diverted_space_node::type()
5790 return "diverted_space_node";
5793 int diverted_space_node::force_tprint()
5798 int diverted_space_node::is_tag()
5803 int diverted_copy_file_node::same(node
*nd
)
5805 return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
5808 const char *diverted_copy_file_node::type()
5810 return "diverted_copy_file_node";
5813 int diverted_copy_file_node::force_tprint()
5818 int diverted_copy_file_node::is_tag()
5823 // Grow the font_table so that its size is > n.
5825 static void grow_font_table(int n
)
5827 assert(n
>= font_table_size
);
5828 font_info
**old_font_table
= font_table
;
5829 int old_font_table_size
= font_table_size
;
5830 font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
5831 if (font_table_size
<= n
)
5832 font_table_size
= n
+ 10;
5833 font_table
= new font_info
*[font_table_size
];
5834 if (old_font_table_size
)
5835 memcpy(font_table
, old_font_table
,
5836 old_font_table_size
*sizeof(font_info
*));
5837 a_delete old_font_table
;
5838 for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
5842 dictionary
font_translation_dictionary(17);
5844 static symbol
get_font_translation(symbol nm
)
5846 void *p
= font_translation_dictionary
.lookup(nm
);
5847 return p
? symbol((char *)p
) : nm
;
5850 dictionary
font_dictionary(50);
5852 static int mount_font_no_translate(int n
, symbol name
, symbol external_name
,
5856 // We store the address of this char in font_dictionary to indicate
5857 // that we've previously tried to mount the font and failed.
5860 void *p
= font_dictionary
.lookup(external_name
);
5863 fm
= font::load_font(external_name
.contents(), ¬_found
, check_only
);
5868 warning(WARN_FONT
, "can't find font `%1'", external_name
.contents());
5869 (void)font_dictionary
.lookup(external_name
, &a_char
);
5872 (void)font_dictionary
.lookup(name
, fm
);
5874 else if (p
== &a_char
) {
5876 error("invalid font `%1'", external_name
.contents());
5884 if (n
>= font_table_size
) {
5885 if (n
- font_table_size
> 1000) {
5886 error("font position too much larger than first unused position");
5891 else if (font_table
[n
] != 0)
5892 delete font_table
[n
];
5893 font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
5894 font_family::invalidate_fontno(n
);
5898 int mount_font(int n
, symbol name
, symbol external_name
)
5901 name
= get_font_translation(name
);
5902 if (external_name
.is_null())
5903 external_name
= name
;
5905 external_name
= get_font_translation(external_name
);
5906 return mount_font_no_translate(n
, name
, external_name
);
5909 int check_font(symbol fam
, symbol name
)
5911 if (check_style(name
))
5912 name
= concat(fam
, name
);
5913 return mount_font_no_translate(0, name
, name
, 1);
5916 int check_style(symbol s
)
5918 int i
= symbol_fontno(s
);
5919 return i
< 0 ? 0 : font_table
[i
]->is_style();
5922 void mount_style(int n
, symbol name
)
5925 if (n
>= font_table_size
) {
5926 if (n
- font_table_size
> 1000) {
5927 error("font position too much larger than first unused position");
5932 else if (font_table
[n
] != 0)
5933 delete font_table
[n
];
5934 font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
5935 font_family::invalidate_fontno(n
);
5938 /* global functions */
5940 void font_translate()
5942 symbol from
= get_name(1);
5943 if (!from
.is_null()) {
5944 symbol to
= get_name();
5945 if (to
.is_null() || from
== to
)
5946 font_translation_dictionary
.remove(from
);
5948 (void)font_translation_dictionary
.lookup(from
, (void *)to
.contents());
5953 void font_position()
5956 if (get_integer(&n
)) {
5958 error("negative font position");
5960 symbol internal_name
= get_name(1);
5961 if (!internal_name
.is_null()) {
5962 symbol external_name
= get_long_name();
5963 mount_font(n
, internal_name
, external_name
); // ignore error
5970 font_family::font_family(symbol s
)
5971 : map_size(10), nm(s
)
5973 map
= new int[map_size
];
5974 for (int i
= 0; i
< map_size
; i
++)
5978 font_family::~font_family()
5983 int font_family::make_definite(int i
)
5986 if (i
< map_size
&& map
[i
] >= 0)
5989 if (i
< font_table_size
&& font_table
[i
] != 0) {
5990 if (i
>= map_size
) {
5991 int old_map_size
= map_size
;
5997 map
= new int[map_size
];
5998 memcpy(map
, old_map
, old_map_size
*sizeof(int));
6000 for (int j
= old_map_size
; j
< map_size
; j
++)
6003 if (font_table
[i
]->is_style()) {
6004 symbol sty
= font_table
[i
]->get_name();
6005 symbol f
= concat(nm
, sty
);
6007 // don't use symbol_fontno, because that might return a style
6008 // and because we don't want to translate the name
6009 for (n
= 0; n
< font_table_size
; n
++)
6010 if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
6011 && !font_table
[n
]->is_style())
6013 if (n
>= font_table_size
) {
6014 n
= next_available_font_position();
6015 if (!mount_font_no_translate(n
, f
, f
))
6031 dictionary
family_dictionary(5);
6033 font_family
*lookup_family(symbol nm
)
6035 font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
6037 f
= new font_family(nm
);
6038 (void)family_dictionary
.lookup(nm
, f
);
6043 void font_family::invalidate_fontno(int n
)
6045 assert(n
>= 0 && n
< font_table_size
);
6046 dictionary_iterator
iter(family_dictionary
);
6049 while (iter
.get(&nam
, (void **)&fam
)) {
6050 int mapsize
= fam
->map_size
;
6053 for (int i
= 0; i
< mapsize
; i
++)
6054 if (fam
->map
[i
] == n
)
6062 if (get_integer(&n
)) {
6064 error("negative font position");
6066 symbol internal_name
= get_name(1);
6067 if (!internal_name
.is_null())
6068 mount_style(n
, internal_name
);
6074 static int get_fontno()
6078 if (tok
.delimiter()) {
6079 symbol s
= get_name(1);
6081 n
= symbol_fontno(s
);
6083 n
= next_available_font_position();
6084 if (!mount_font(n
, s
))
6087 return curenv
->get_family()->make_definite(n
);
6090 else if (get_integer(&n
)) {
6091 if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
6092 error("bad font number");
6094 return curenv
->get_family()->make_definite(n
);
6099 static int underline_fontno
= 2;
6101 void underline_font()
6103 int n
= get_fontno();
6105 underline_fontno
= n
;
6109 int get_underline_fontno()
6111 return underline_fontno
;
6114 void define_font_special_character()
6116 int n
= get_fontno();
6121 symbol f
= font_table
[n
]->get_name();
6122 do_define_character(CHAR_FONT_SPECIAL
, f
.contents());
6125 void remove_font_special_character()
6127 int n
= get_fontno();
6132 symbol f
= font_table
[n
]->get_name();
6133 while (!tok
.newline() && !tok
.eof()) {
6134 if (!tok
.space() && !tok
.tab()) {
6135 charinfo
*s
= tok
.get_char(1);
6136 string
gl(f
.contents());
6138 gl
+= s
->nm
.contents();
6140 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
6143 macro
*m
= ci
->set_macro(0);
6152 static void read_special_fonts(special_font_list
**sp
)
6154 special_font_list
*s
= *sp
;
6157 special_font_list
*tem
= s
;
6161 special_font_list
**p
= sp
;
6163 int i
= get_fontno();
6165 special_font_list
*tem
= new special_font_list
;
6174 void font_special_request()
6176 int n
= get_fontno();
6178 read_special_fonts(&font_table
[n
]->sf
);
6182 void special_request()
6184 read_special_fonts(&global_special_fonts
);
6188 int next_available_font_position()
6191 for (i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
6196 int symbol_fontno(symbol s
)
6198 s
= get_font_translation(s
);
6199 for (int i
= 0; i
< font_table_size
; i
++)
6200 if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
6205 int is_good_fontno(int n
)
6207 return n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0;
6210 int get_bold_fontno(int n
)
6212 if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
6214 if (font_table
[n
]->get_bold(&offset
))
6215 return offset
.to_units() + 1;
6223 hunits
env_digit_width(environment
*env
)
6225 node
*n
= make_glyph_node(charset_table
['0'], env
);
6227 hunits x
= n
->width();
6235 hunits
env_space_width(environment
*env
)
6237 int fn
= env_definite_font(env
);
6238 font_size fs
= env
->get_font_size();
6239 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6240 return scale(fs
.to_units()/3, env
->get_space_size(), 12);
6242 return font_table
[fn
]->get_space_width(fs
, env
->get_space_size());
6245 hunits
env_sentence_space_width(environment
*env
)
6247 int fn
= env_definite_font(env
);
6248 font_size fs
= env
->get_font_size();
6249 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6250 return scale(fs
.to_units()/3, env
->get_sentence_space_size(), 12);
6252 return font_table
[fn
]->get_space_width(fs
, env
->get_sentence_space_size());
6255 hunits
env_half_narrow_space_width(environment
*env
)
6257 int fn
= env_definite_font(env
);
6258 font_size fs
= env
->get_font_size();
6259 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6262 return font_table
[fn
]->get_half_narrow_space_width(fs
);
6265 hunits
env_narrow_space_width(environment
*env
)
6267 int fn
= env_definite_font(env
);
6268 font_size fs
= env
->get_font_size();
6269 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6272 return font_table
[fn
]->get_narrow_space_width(fs
);
6277 int n
= get_fontno();
6280 if (tok
.delimiter()) {
6281 int f
= get_fontno();
6284 if (has_arg() && get_number(&offset
, 'u') && offset
>= 1)
6285 font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
6287 font_table
[f
]->conditional_unbold(n
);
6292 if (get_number(&offset
, 'u') && offset
>= 1)
6293 font_table
[n
]->set_bold(hunits(offset
- 1));
6295 font_table
[n
]->unbold();
6299 font_table
[n
]->unbold();
6304 track_kerning_function::track_kerning_function() : non_zero(0)
6308 track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
6309 int max_s
, hunits max_a
)
6310 : non_zero(1), min_size(min_s
), min_amount(min_a
), max_size(max_s
),
6315 int track_kerning_function::operator==(const track_kerning_function
&tk
)
6319 && min_size
== tk
.min_size
6320 && min_amount
== tk
.min_amount
6321 && max_size
== tk
.max_size
6322 && max_amount
== tk
.max_amount
);
6324 return !tk
.non_zero
;
6327 int track_kerning_function::operator!=(const track_kerning_function
&tk
)
6330 return (!tk
.non_zero
6331 || min_size
!= tk
.min_size
6332 || min_amount
!= tk
.min_amount
6333 || max_size
!= tk
.max_size
6334 || max_amount
!= tk
.max_amount
);
6339 hunits
track_kerning_function::compute(int size
)
6342 if (max_size
<= min_size
)
6344 else if (size
<= min_size
)
6346 else if (size
>= max_size
)
6349 return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
6350 + scale(min_amount
, max_size
- size
, max_size
- min_size
));
6358 int n
= get_fontno();
6361 hunits min_a
, max_a
;
6363 && get_number(&min_s
, 'z')
6364 && get_hunits(&min_a
, 'p')
6365 && get_number(&max_s
, 'z')
6366 && get_hunits(&max_a
, 'p')) {
6367 track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
6368 font_table
[n
]->set_track_kern(tk
);
6371 track_kerning_function tk
;
6372 font_table
[n
]->set_track_kern(tk
);
6378 void constant_space()
6380 int n
= get_fontno();
6383 if (!has_arg() || !get_integer(&x
))
6384 font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
6386 if (!has_arg() || !get_number(&y
, 'z'))
6387 font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
6389 font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
6401 if (has_arg() && get_integer(&lig
) && lig
>= 0 && lig
<= 2)
6402 global_ligature_mode
= lig
;
6404 global_ligature_mode
= 1;
6411 if (has_arg() && get_integer(&k
))
6412 global_kern_mode
= k
!= 0;
6414 global_kern_mode
= 1;
6418 void set_soft_hyphen_char()
6420 soft_hyphen_char
= get_optional_char();
6421 if (!soft_hyphen_char
)
6422 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);
6428 if (suppress_output_flag
)
6429 the_output
= new suppress_output_file
;
6430 else if (ascii_output_flag
)
6431 the_output
= new ascii_output_file
;
6433 the_output
= new troff_output_file
;
6436 class next_available_font_position_reg
: public reg
{
6438 const char *get_string();
6441 const char *next_available_font_position_reg::get_string()
6443 return i_to_a(next_available_font_position());
6446 class printing_reg
: public reg
{
6448 const char *get_string();
6451 const char *printing_reg::get_string()
6454 return the_output
->is_printing() ? "1" : "0";
6459 void init_node_requests()
6461 init_request("bd", bold_font
);
6462 init_request("cs", constant_space
);
6463 init_request("fp", font_position
);
6464 init_request("fschar", define_font_special_character
);
6465 init_request("fspecial", font_special_request
);
6466 init_request("ftr", font_translate
);
6467 init_request("kern", kern_request
);
6468 init_request("lg", ligature
);
6469 init_request("rfschar", remove_font_special_character
);
6470 init_request("shc", set_soft_hyphen_char
);
6471 init_request("special", special_request
);
6472 init_request("sty", style
);
6473 init_request("tkf", track_kern
);
6474 init_request("uf", underline_font
);
6475 number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
6476 number_reg_dictionary
.define(".kern",
6477 new constant_int_reg(&global_kern_mode
));
6478 number_reg_dictionary
.define(".lg",
6479 new constant_int_reg(&global_ligature_mode
));
6480 number_reg_dictionary
.define(".P", new printing_reg
);
6481 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);