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 */
65 * how many boundaries of images have been written? Useful for
70 static int suppress_start_page
= 0;
74 symbol
HYPHEN_SYMBOL("hy");
76 // Character used when a hyphen is inserted at a line break.
77 static charinfo
*soft_hyphen_char
;
79 enum constant_space_type
{
81 CONSTANT_SPACE_RELATIVE
,
82 CONSTANT_SPACE_ABSOLUTE
85 struct special_font_list
{
87 special_font_list
*next
;
90 special_font_list
*global_special_fonts
;
91 static int global_ligature_mode
= 1;
92 static int global_kern_mode
= 1;
94 class track_kerning_function
{
101 track_kerning_function();
102 track_kerning_function(units
, hunits
, units
, hunits
);
103 int operator==(const track_kerning_function
&);
104 int operator!=(const track_kerning_function
&);
105 hunits
compute(int point_size
);
108 // embolden fontno when this is the current font
110 struct conditional_bold
{
111 conditional_bold
*next
;
114 conditional_bold(int, hunits
, conditional_bold
* = 0);
125 symbol internal_name
;
126 symbol external_name
;
130 track_kerning_function track_kern
;
131 constant_space_type is_constant_spaced
;
132 units constant_space
;
133 int last_ligature_mode
;
135 conditional_bold
*cond_bold_list
;
138 special_font_list
*sf
;
139 font_info(symbol
, int, symbol
, font
*);
140 int contains(charinfo
*);
141 void set_bold(hunits
);
143 void set_conditional_bold(int, hunits
);
144 void conditional_unbold(int);
145 void set_track_kern(track_kerning_function
&);
146 void set_constant_space(constant_space_type
, units
= 0);
147 int is_named(symbol
);
149 tfont
*get_tfont(font_size
, int, int, int);
150 hunits
get_space_width(font_size
, int);
151 hunits
get_narrow_space_width(font_size
);
152 hunits
get_half_narrow_space_width(font_size
);
153 int get_bold(hunits
*);
156 friend symbol
get_font_name(int, environment
*);
157 friend symbol
get_style_name(int);
167 char is_constant_spaced
;
171 hunits track_kern
; // add this to the width
172 hunits constant_space_width
;
176 tfont_spec(symbol
, int, font
*, font_size
, int, int);
177 tfont_spec(const tfont_spec
&spec
) { *this = spec
; }
179 int operator==(const tfont_spec
&);
180 friend tfont
*font_info::get_tfont(font_size fs
, int, int, int);
183 class tfont
: public tfont_spec
{
184 static tfont
*tfont_list
;
186 tfont
*plain_version
;
189 int contains(charinfo
*);
190 hunits
get_width(charinfo
*c
);
191 int get_bold(hunits
*);
192 int get_constant_space(hunits
*);
193 hunits
get_track_kern();
195 font_size
get_size();
197 charinfo
*get_lig(charinfo
*c1
, charinfo
*c2
);
198 int get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
);
199 int get_input_position();
200 int get_character_type(charinfo
*);
203 vunits
get_char_height(charinfo
*);
204 vunits
get_char_depth(charinfo
*);
205 hunits
get_char_skew(charinfo
*);
206 hunits
get_italic_correction(charinfo
*);
207 hunits
get_left_italic_correction(charinfo
*);
208 hunits
get_subscript_correction(charinfo
*);
209 friend tfont
*make_tfont(tfont_spec
&);
212 inline int env_definite_font(environment
*env
)
214 return env
->get_family()->make_definite(env
->get_font());
217 /* font_info functions */
219 static font_info
**font_table
= 0;
220 static int font_table_size
= 0;
222 font_info::font_info(symbol nm
, int n
, symbol enm
, font
*f
)
223 : last_tfont(0), number(n
), last_size(0),
224 internal_name(nm
), external_name(enm
), fm(f
),
225 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE
), last_ligature_mode(1),
226 last_kern_mode(1), cond_bold_list(0), sf(0)
230 inline int font_info::contains(charinfo
*ci
)
232 return fm
!= 0 && fm
->contains(ci
->get_index());
235 inline int font_info::is_special()
237 return fm
!= 0 && fm
->is_special();
240 inline int font_info::is_style()
245 tfont
*make_tfont(tfont_spec
&spec
)
247 for (tfont
*p
= tfont::tfont_list
; p
; p
= p
->next
)
250 return new tfont(spec
);
253 // this is the current_font, fontno is where we found the character,
254 // presumably a special font
256 tfont
*font_info::get_tfont(font_size fs
, int height
, int slant
, int fontno
)
258 if (last_tfont
== 0 || fs
!= last_size
259 || height
!= last_height
|| slant
!= last_slant
260 || global_ligature_mode
!= last_ligature_mode
261 || global_kern_mode
!= last_kern_mode
262 || fontno
!= number
) {
263 font_info
*f
= font_table
[fontno
];
264 tfont_spec
spec(f
->external_name
, f
->number
, f
->fm
, fs
, height
, slant
);
265 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
266 if (p
->fontno
== fontno
) {
268 spec
.bold_offset
= p
->offset
;
271 if (!spec
.is_bold
&& is_bold
) {
273 spec
.bold_offset
= bold_offset
;
275 spec
.track_kern
= track_kern
.compute(fs
.to_scaled_points());
276 spec
.ligature_mode
= global_ligature_mode
;
277 spec
.kern_mode
= global_kern_mode
;
278 switch (is_constant_spaced
) {
279 case CONSTANT_SPACE_NONE
:
281 case CONSTANT_SPACE_ABSOLUTE
:
282 spec
.is_constant_spaced
= 1;
283 spec
.constant_space_width
= constant_space
;
285 case CONSTANT_SPACE_RELATIVE
:
286 spec
.is_constant_spaced
= 1;
287 spec
.constant_space_width
288 = scale(constant_space
*fs
.to_scaled_points(),
295 if (fontno
!= number
)
296 return make_tfont(spec
);
297 last_tfont
= make_tfont(spec
);
299 last_height
= height
;
301 last_ligature_mode
= global_ligature_mode
;
302 last_kern_mode
= global_kern_mode
;
307 int font_info::get_bold(hunits
*res
)
317 void font_info::unbold()
325 void font_info::set_bold(hunits offset
)
327 if (!is_bold
|| offset
!= bold_offset
) {
329 bold_offset
= offset
;
334 void font_info::set_conditional_bold(int fontno
, hunits offset
)
336 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
337 if (p
->fontno
== fontno
) {
338 if (offset
!= p
->offset
) {
344 cond_bold_list
= new conditional_bold(fontno
, offset
, cond_bold_list
);
347 conditional_bold::conditional_bold(int f
, hunits h
, conditional_bold
*x
)
348 : next(x
), fontno(f
), offset(h
)
352 void font_info::conditional_unbold(int fontno
)
354 for (conditional_bold
**p
= &cond_bold_list
; *p
; p
= &(*p
)->next
)
355 if ((*p
)->fontno
== fontno
) {
356 conditional_bold
*tem
= *p
;
364 void font_info::set_constant_space(constant_space_type type
, units x
)
366 if (type
!= is_constant_spaced
367 || (type
!= CONSTANT_SPACE_NONE
&& x
!= constant_space
)) {
369 is_constant_spaced
= type
;
374 void font_info::set_track_kern(track_kerning_function
&tk
)
376 if (track_kern
!= tk
) {
382 void font_info::flush()
387 int font_info::is_named(symbol s
)
389 return internal_name
== s
;
392 symbol
font_info::get_name()
394 return internal_name
;
397 symbol
get_font_name(int fontno
, environment
*env
)
399 symbol f
= font_table
[fontno
]->get_name();
400 if (font_table
[fontno
]->is_style()) {
401 return concat(env
->get_family()->nm
, f
);
406 symbol
get_style_name(int fontno
)
408 if (font_table
[fontno
]->is_style())
409 return font_table
[fontno
]->get_name();
414 hunits
font_info::get_space_width(font_size fs
, int space_sz
)
416 if (is_constant_spaced
== CONSTANT_SPACE_NONE
)
417 return scale(hunits(fm
->get_space_width(fs
.to_scaled_points())),
419 else if (is_constant_spaced
== CONSTANT_SPACE_ABSOLUTE
)
420 return constant_space
;
422 return scale(constant_space
*fs
.to_scaled_points(),
423 units_per_inch
, 36*72*sizescale
);
426 hunits
font_info::get_narrow_space_width(font_size fs
)
428 charinfo
*ci
= get_charinfo(symbol("|"));
429 if (fm
->contains(ci
->get_index()))
430 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
432 return hunits(fs
.to_units()/6);
435 hunits
font_info::get_half_narrow_space_width(font_size fs
)
437 charinfo
*ci
= get_charinfo(symbol("^"));
438 if (fm
->contains(ci
->get_index()))
439 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
441 return hunits(fs
.to_units()/12);
446 tfont_spec::tfont_spec(symbol nm
, int n
, font
*f
,
447 font_size s
, int h
, int sl
)
448 : name(nm
), input_position(n
), fm(f
), size(s
),
449 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
452 if (height
== size
.to_scaled_points())
456 int tfont_spec::operator==(const tfont_spec
&spec
)
460 && input_position
== spec
.input_position
462 && height
== spec
.height
463 && slant
== spec
.slant
465 ? (spec
.is_bold
&& bold_offset
== spec
.bold_offset
)
467 && track_kern
== spec
.track_kern
468 && (is_constant_spaced
469 ? (spec
.is_constant_spaced
470 && constant_space_width
== spec
.constant_space_width
)
471 : !spec
.is_constant_spaced
)
472 && ligature_mode
== spec
.ligature_mode
473 && kern_mode
== spec
.kern_mode
)
479 tfont_spec
tfont_spec::plain()
481 return tfont_spec(name
, input_position
, fm
, size
, height
, slant
);
484 hunits
tfont::get_width(charinfo
*c
)
486 if (is_constant_spaced
)
487 return constant_space_width
;
489 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
490 + track_kern
+ bold_offset
);
492 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
496 vunits
tfont::get_char_height(charinfo
*c
)
498 vunits v
= fm
->get_height(c
->get_index(), size
.to_scaled_points());
499 if (height
!= 0 && height
!= size
.to_scaled_points())
500 return scale(v
, height
, size
.to_scaled_points());
505 vunits
tfont::get_char_depth(charinfo
*c
)
507 vunits v
= fm
->get_depth(c
->get_index(), size
.to_scaled_points());
508 if (height
!= 0 && height
!= size
.to_scaled_points())
509 return scale(v
, height
, size
.to_scaled_points());
514 hunits
tfont::get_char_skew(charinfo
*c
)
516 return hunits(fm
->get_skew(c
->get_index(), size
.to_scaled_points(), slant
));
519 hunits
tfont::get_italic_correction(charinfo
*c
)
521 return hunits(fm
->get_italic_correction(c
->get_index(), size
.to_scaled_points()));
524 hunits
tfont::get_left_italic_correction(charinfo
*c
)
526 return hunits(fm
->get_left_italic_correction(c
->get_index(),
527 size
.to_scaled_points()));
530 hunits
tfont::get_subscript_correction(charinfo
*c
)
532 return hunits(fm
->get_subscript_correction(c
->get_index(),
533 size
.to_scaled_points()));
536 inline int tfont::get_input_position()
538 return input_position
;
541 inline int tfont::contains(charinfo
*ci
)
543 return fm
->contains(ci
->get_index());
546 inline int tfont::get_character_type(charinfo
*ci
)
548 return fm
->get_character_type(ci
->get_index());
551 inline int tfont::get_bold(hunits
*res
)
561 inline int tfont::get_constant_space(hunits
*res
)
563 if (is_constant_spaced
) {
564 *res
= constant_space_width
;
571 inline hunits
tfont::get_track_kern()
576 inline tfont
*tfont::get_plain()
578 return plain_version
;
581 inline font_size
tfont::get_size()
586 inline symbol
tfont::get_name()
591 inline int tfont::get_height()
596 inline int tfont::get_slant()
601 symbol
SYMBOL_ff("ff");
602 symbol
SYMBOL_fi("fi");
603 symbol
SYMBOL_fl("fl");
604 symbol
SYMBOL_Fi("Fi");
605 symbol
SYMBOL_Fl("Fl");
607 charinfo
*tfont::get_lig(charinfo
*c1
, charinfo
*c2
)
609 if (ligature_mode
== 0)
612 if (c1
->get_ascii_code() == 'f') {
613 switch (c2
->get_ascii_code()) {
615 if (fm
->has_ligature(font::LIG_ff
))
616 ci
= get_charinfo(SYMBOL_ff
);
619 if (fm
->has_ligature(font::LIG_fi
))
620 ci
= get_charinfo(SYMBOL_fi
);
623 if (fm
->has_ligature(font::LIG_fl
))
624 ci
= get_charinfo(SYMBOL_fl
);
628 else if (ligature_mode
!= 2 && c1
->nm
== SYMBOL_ff
) {
629 switch (c2
->get_ascii_code()) {
631 if (fm
->has_ligature(font::LIG_ffi
))
632 ci
= get_charinfo(SYMBOL_Fi
);
635 if (fm
->has_ligature(font::LIG_ffl
))
636 ci
= get_charinfo(SYMBOL_Fl
);
640 if (ci
!= 0 && fm
->contains(ci
->get_index()))
645 inline int tfont::get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
)
650 int n
= fm
->get_kern(c1
->get_index(),
652 size
.to_scaled_points());
662 tfont
*tfont::tfont_list
= 0;
664 tfont::tfont(tfont_spec
&spec
) : tfont_spec(spec
)
668 tfont_spec plain_spec
= plain();
670 for (p
= tfont_list
; p
; p
= p
->next
)
671 if (*p
== plain_spec
) {
676 plain_version
= new tfont(plain_spec
);
681 class real_output_file
: public output_file
{
682 #ifndef POPEN_MISSING
685 int printing
; // decision via optional page list
686 int output_on
; // \O[0] or \O[1] escape calls
687 virtual void really_transparent_char(unsigned char) = 0;
688 virtual void really_print_line(hunits x
, vunits y
, node
*n
,
689 vunits before
, vunits after
, hunits width
) = 0;
690 virtual void really_begin_page(int pageno
, vunits page_length
) = 0;
691 virtual void really_copy_file(hunits x
, vunits y
, const char *filename
);
692 virtual void really_put_filename(const char *filename
);
693 virtual void really_on();
694 virtual void really_off();
700 void transparent_char(unsigned char);
701 void print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
702 void begin_page(int pageno
, vunits page_length
);
703 void put_filename(const char *filename
);
708 void copy_file(hunits x
, vunits y
, const char *filename
);
711 class suppress_output_file
: public real_output_file
{
713 suppress_output_file();
714 void really_transparent_char(unsigned char);
715 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
716 void really_begin_page(int pageno
, vunits page_length
);
719 class ascii_output_file
: public real_output_file
{
722 void really_transparent_char(unsigned char);
723 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
724 void really_begin_page(int pageno
, vunits page_length
);
725 void outc(unsigned char c
);
726 void outs(const char *s
);
729 void ascii_output_file::outc(unsigned char c
)
734 void ascii_output_file::outs(const char *s
)
744 class troff_output_file
: public real_output_file
{
753 tfont
*current_tfont
;
754 color
*current_fill_color
;
755 color
*current_glyph_color
;
756 int current_font_number
;
757 symbol
*font_position
;
759 enum { TBUF_SIZE
= 256 };
760 char tbuf
[TBUF_SIZE
];
768 void put(unsigned char c
);
770 void put(unsigned int i
);
771 void put(const char *s
);
772 void set_font(tfont
*tf
);
776 ~troff_output_file();
777 void trailer(vunits page_length
);
778 void put_char(charinfo
*, tfont
*, color
*, color
*);
779 void put_char_width(charinfo
*, tfont
*, color
*, color
*, hunits
, hunits
);
782 void moveto(hunits
, vunits
);
783 void start_special(tfont
*, color
*, color
*, int = 0);
784 void start_special();
785 void special_char(unsigned char c
);
788 void really_transparent_char(unsigned char c
);
789 void really_print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
790 void really_begin_page(int pageno
, vunits page_length
);
791 void really_copy_file(hunits x
, vunits y
, const char *filename
);
792 void really_put_filename(const char *filename
);
795 void draw(char, hvpair
*, int, font_size
, color
*, color
*);
796 void determine_line_limits (char code
, hvpair
*point
, int npoints
);
797 void check_charinfo(tfont
*tf
, charinfo
*ci
);
798 void glyph_color(color
*c
);
799 void fill_color(color
*c
);
800 int get_hpos() { return hpos
; }
801 int get_vpos() { return vpos
; }
802 void add_to_tag_list(string s
);
803 friend void space_char_hmotion_node::tprint(troff_output_file
*);
804 friend void unbreakable_space_node::tprint(troff_output_file
*);
807 static void put_string(const char *s
, FILE *fp
)
809 for (; *s
!= '\0'; ++s
)
813 inline void troff_output_file::put(char c
)
818 inline void troff_output_file::put(unsigned char c
)
823 inline void troff_output_file::put(const char *s
)
828 inline void troff_output_file::put(int i
)
830 put_string(i_to_a(i
), fp
);
833 inline void troff_output_file::put(unsigned int i
)
835 put_string(ui_to_a(i
), fp
);
838 void troff_output_file::start_special(tfont
*tf
, color
*gcol
, color
*fcol
,
850 void troff_output_file::start_special()
857 void troff_output_file::special_char(unsigned char c
)
864 void troff_output_file::end_special()
869 inline void troff_output_file::moveto(hunits h
, vunits v
)
875 void troff_output_file::really_print_line(hunits x
, vunits y
, node
*n
,
876 vunits before
, vunits after
, hunits
)
880 // Check whether we should push the current troff state and use
881 // the state at the start of the invocation of this diversion.
882 if (n
->div_nest_level
> cur_div_level
&& n
->push_state
) {
883 state
.push_state(n
->push_state
);
884 cur_div_level
= n
->div_nest_level
;
886 // Has the current diversion level decreased? Then we must pop the
888 while (n
->div_nest_level
< cur_div_level
) {
890 cur_div_level
= n
->div_nest_level
;
892 // Now check whether the state has changed.
893 if ((is_on() || n
->force_tprint())
894 && (state
.changed(n
->state
) || n
->is_tag() || n
->is_special
)) {
899 state
.flush(fp
, n
->state
, tag_list
);
900 tag_list
= string("");
907 // This ensures that transparent throughput will have a more predictable
913 put(before
.to_units());
915 put(after
.to_units());
919 inline void troff_output_file::word_marker()
926 inline void troff_output_file::right(hunits n
)
928 hpos
+= n
.to_units();
931 inline void troff_output_file::down(vunits n
)
933 vpos
+= n
.to_units();
936 void troff_output_file::do_motion()
947 if (hpos
!= output_hpos
) {
948 units n
= hpos
- output_hpos
;
949 if (n
> 0 && n
< hpos
) {
959 if (vpos
!= output_vpos
) {
960 units n
= vpos
- output_vpos
;
961 if (n
> 0 && n
< vpos
) {
977 void troff_output_file::flush_tbuf()
993 check_output_limits(hpos
, vpos
);
994 check_output_limits(hpos
, vpos
- current_size
);
996 for (int i
= 0; i
< tbuf_len
; i
++)
1002 void troff_output_file::check_charinfo(tfont
*tf
, charinfo
*ci
)
1007 int height
= tf
->get_char_height(ci
).to_units();
1008 int width
= tf
->get_width(ci
).to_units()
1009 + tf
->get_italic_correction(ci
).to_units();
1010 int depth
= tf
->get_char_depth(ci
).to_units();
1011 check_output_limits(output_hpos
, output_vpos
- height
);
1012 check_output_limits(output_hpos
+ width
, output_vpos
+ depth
);
1015 void troff_output_file::put_char_width(charinfo
*ci
, tfont
*tf
,
1016 color
*gcol
, color
*fcol
,
1019 int kk
= k
.to_units();
1022 hpos
+= w
.to_units() + kk
;
1026 unsigned char c
= ci
->get_ascii_code();
1032 check_charinfo(tf
, ci
);
1033 if (ci
->numbered()) {
1035 put(ci
->get_number());
1039 const char *s
= ci
->nm
.contents();
1048 hpos
+= w
.to_units() + kk
;
1050 else if (tcommand_flag
) {
1051 if (tbuf_len
> 0 && hpos
== output_hpos
&& vpos
== output_vpos
1052 && (!gcol
|| gcol
== current_glyph_color
)
1053 && (!fcol
|| fcol
== current_fill_color
)
1055 && tbuf_len
< TBUF_SIZE
) {
1056 check_charinfo(tf
, ci
);
1057 tbuf
[tbuf_len
++] = c
;
1058 output_hpos
+= w
.to_units() + kk
;
1066 check_charinfo(tf
, ci
);
1067 tbuf
[tbuf_len
++] = c
;
1068 output_hpos
+= w
.to_units() + kk
;
1074 int n
= hpos
- output_hpos
;
1075 check_charinfo(tf
, ci
);
1076 // check_output_limits(output_hpos, output_vpos);
1077 if (vpos
== output_vpos
1078 && (!gcol
|| gcol
== current_glyph_color
)
1079 && (!fcol
|| fcol
== current_fill_color
)
1080 && n
> 0 && n
< 100 && !force_motion
) {
1081 put(char(n
/10 + '0'));
1082 put(char(n
%10 + '0'));
1093 hpos
+= w
.to_units() + kk
;
1097 void troff_output_file::put_char(charinfo
*ci
, tfont
*tf
,
1098 color
*gcol
, color
*fcol
)
1104 unsigned char c
= ci
->get_ascii_code();
1110 if (ci
->numbered()) {
1112 put(ci
->get_number());
1116 const char *s
= ci
->nm
.contents();
1127 int n
= hpos
- output_hpos
;
1128 if (vpos
== output_vpos
1129 && (!gcol
|| gcol
== current_glyph_color
)
1130 && (!fcol
|| fcol
== current_fill_color
)
1131 && n
> 0 && n
< 100) {
1132 put(char(n
/10 + '0'));
1133 put(char(n
%10 + '0'));
1148 // set_font calls `flush_tbuf' if necessary.
1150 void troff_output_file::set_font(tfont
*tf
)
1152 if (current_tfont
== tf
)
1155 int n
= tf
->get_input_position();
1156 symbol nm
= tf
->get_name();
1157 if (n
>= nfont_positions
|| font_position
[n
] != nm
) {
1163 if (n
>= nfont_positions
) {
1164 int old_nfont_positions
= nfont_positions
;
1165 symbol
*old_font_position
= font_position
;
1166 nfont_positions
*= 3;
1167 nfont_positions
/= 2;
1168 if (nfont_positions
<= n
)
1169 nfont_positions
= n
+ 10;
1170 font_position
= new symbol
[nfont_positions
];
1171 memcpy(font_position
, old_font_position
,
1172 old_nfont_positions
*sizeof(symbol
));
1173 a_delete old_font_position
;
1175 font_position
[n
] = nm
;
1177 if (current_font_number
!= n
) {
1181 current_font_number
= n
;
1183 int size
= tf
->get_size().to_scaled_points();
1184 if (current_size
!= size
) {
1188 current_size
= size
;
1190 int slant
= tf
->get_slant();
1191 if (current_slant
!= slant
) {
1195 current_slant
= slant
;
1197 int height
= tf
->get_height();
1198 if (current_height
!= height
) {
1200 put(height
== 0 ? current_size
: height
);
1202 current_height
= height
;
1207 // fill_color calls `flush_tbuf' and `do_motion' if necessary.
1209 void troff_output_file::fill_color(color
*col
)
1211 if (!col
|| current_fill_color
== col
)
1213 current_fill_color
= col
;
1219 unsigned int components
[4];
1221 cs
= col
->get_components(components
);
1260 // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1262 void troff_output_file::glyph_color(color
*col
)
1264 if (!col
|| current_glyph_color
== col
)
1266 current_glyph_color
= col
;
1270 // grotty doesn't like a color command if the vertical position is zero.
1273 unsigned int components
[4];
1275 cs
= col
->get_components(components
);
1314 void troff_output_file::add_to_tag_list(string s
)
1316 if (tag_list
== string(""))
1319 tag_list
+= string("\n");
1324 // determine_line_limits - works out the smallest box which will contain
1325 // the entity, code, built from the point array.
1326 void troff_output_file::determine_line_limits(char code
, hvpair
*point
,
1337 // only the h field is used when defining a circle
1338 check_output_limits(output_hpos
,
1339 output_vpos
- point
[0].h
.to_units()/2);
1340 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1341 output_vpos
+ point
[0].h
.to_units()/2);
1345 check_output_limits(output_hpos
,
1346 output_vpos
- point
[0].v
.to_units()/2);
1347 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1348 output_vpos
+ point
[0].v
.to_units()/2);
1354 check_output_limits(x
, y
);
1355 for (i
= 0; i
< npoints
; i
++) {
1356 x
+= point
[i
].h
.to_units();
1357 y
+= point
[i
].v
.to_units();
1358 check_output_limits(x
, y
);
1364 for (i
= 0; i
< npoints
; i
++) {
1365 x
+= point
[i
].h
.to_units();
1366 y
+= point
[i
].v
.to_units();
1367 check_output_limits(x
, y
);
1373 int minx
, miny
, maxx
, maxy
;
1376 p
[0] = point
[0].h
.to_units();
1377 p
[1] = point
[0].v
.to_units();
1378 p
[2] = point
[1].h
.to_units();
1379 p
[3] = point
[1].v
.to_units();
1380 if (adjust_arc_center(p
, c
)) {
1381 check_output_arc_limits(x
, y
,
1382 p
[0], p
[1], p
[2], p
[3],
1384 &minx
, &maxx
, &miny
, &maxy
);
1385 check_output_limits(minx
, miny
);
1386 check_output_limits(maxx
, maxy
);
1393 check_output_limits(x
, y
);
1394 for (i
= 0; i
< npoints
; i
++) {
1395 x
+= point
[i
].h
.to_units();
1396 y
+= point
[i
].v
.to_units();
1397 check_output_limits(x
, y
);
1403 for (i
= 0; i
< npoints
; i
++) {
1404 x
+= point
[i
].h
.to_units();
1405 y
+= point
[i
].v
.to_units();
1406 check_output_limits(x
, y
);
1411 void troff_output_file::draw(char code
, hvpair
*point
, int npoints
,
1412 font_size fsize
, color
*gcol
, color
*fcol
)
1420 int size
= fsize
.to_scaled_points();
1421 if (current_size
!= size
) {
1425 current_size
= size
;
1432 put(point
[0].h
.to_units());
1435 for (i
= 0; i
< npoints
; i
++) {
1437 put(point
[i
].h
.to_units());
1439 put(point
[i
].v
.to_units());
1441 determine_line_limits(code
, point
, npoints
);
1444 for (i
= 0; i
< npoints
; i
++)
1445 output_hpos
+= point
[i
].h
.to_units();
1448 for (i
= 0; i
< npoints
; i
++)
1449 output_vpos
+= point
[i
].v
.to_units();
1456 void troff_output_file::really_on()
1463 void troff_output_file::really_off()
1468 void troff_output_file::really_put_filename(const char *filename
)
1476 void troff_output_file::really_begin_page(int pageno
, vunits page_length
)
1480 if (page_length
> V0
) {
1482 put(page_length
.to_units());
1489 current_font_number
= -1;
1491 // current_height = 0;
1492 // current_slant = 0;
1498 for (int i
= 0; i
< nfont_positions
; i
++)
1499 font_position
[i
] = NULL_SYMBOL
;
1505 void troff_output_file::really_copy_file(hunits x
, vunits y
,
1506 const char *filename
)
1512 FILE *ifp
= include_search_path
.open_file_cautious(filename
);
1514 error("can't open `%1': %2", filename
, strerror(errno
));
1517 while ((c
= getc(ifp
)) != EOF
)
1524 current_font_number
= -1;
1525 for (int i
= 0; i
< nfont_positions
; i
++)
1526 font_position
[i
] = NULL_SYMBOL
;
1529 void troff_output_file::really_transparent_char(unsigned char c
)
1534 troff_output_file::~troff_output_file()
1536 a_delete font_position
;
1539 void troff_output_file::trailer(vunits page_length
)
1542 if (page_length
> V0
) {
1545 put(page_length
.to_units());
1551 troff_output_file::troff_output_file()
1552 : current_slant(0), current_height(0), current_fill_color(0),
1553 current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0),
1556 font_position
= new symbol
[nfont_positions
];
1561 put(units_per_inch
);
1572 output_file
*the_output
= 0;
1574 output_file::output_file()
1578 output_file::~output_file()
1582 void output_file::trailer(vunits
)
1586 void output_file::put_filename(const char *)
1590 void output_file::on()
1594 void output_file::off()
1598 real_output_file::real_output_file()
1599 : printing(0), output_on(1)
1601 #ifndef POPEN_MISSING
1603 if ((fp
= popen(pipe_command
, POPEN_WT
)) != 0) {
1607 error("pipe open failed: %1", strerror(errno
));
1610 #endif /* not POPEN_MISSING */
1614 real_output_file::~real_output_file()
1618 // To avoid looping, set fp to 0 before calling fatal().
1619 if (ferror(fp
) || fflush(fp
) < 0) {
1621 fatal("error writing output file");
1623 #ifndef POPEN_MISSING
1625 int result
= pclose(fp
);
1628 fatal("pclose failed");
1629 if (!WIFEXITED(result
))
1630 error("output process `%1' got fatal signal %2",
1632 WIFSIGNALED(result
) ? WTERMSIG(result
) : WSTOPSIG(result
));
1634 int exit_status
= WEXITSTATUS(result
);
1635 if (exit_status
!= 0)
1636 error("output process `%1' exited with status %2",
1637 pipe_command
, exit_status
);
1641 #endif /* not POPEN MISSING */
1642 if (fclose(fp
) < 0) {
1644 fatal("error closing output file");
1648 void real_output_file::flush()
1651 fatal("error writing output file");
1654 int real_output_file::is_printing()
1659 void real_output_file::begin_page(int pageno
, vunits page_length
)
1661 printing
= in_output_page_list(pageno
);
1663 really_begin_page(pageno
, page_length
);
1666 void real_output_file::copy_file(hunits x
, vunits y
, const char *filename
)
1668 if (printing
&& output_on
)
1669 really_copy_file(x
, y
, filename
);
1670 check_output_limits(x
.to_units(), y
.to_units());
1673 void real_output_file::transparent_char(unsigned char c
)
1675 if (printing
&& output_on
)
1676 really_transparent_char(c
);
1679 void real_output_file::print_line(hunits x
, vunits y
, node
*n
,
1680 vunits before
, vunits after
, hunits width
)
1683 really_print_line(x
, y
, n
, before
, after
, width
);
1684 delete_node_list(n
);
1687 void real_output_file::really_copy_file(hunits
, vunits
, const char *)
1692 void real_output_file::put_filename(const char *filename
)
1694 really_put_filename(filename
);
1697 void real_output_file::really_put_filename(const char *)
1701 void real_output_file::on()
1708 void real_output_file::off()
1714 int real_output_file::is_on()
1719 void real_output_file::really_on()
1723 void real_output_file::really_off()
1727 /* ascii_output_file */
1729 void ascii_output_file::really_transparent_char(unsigned char c
)
1734 void ascii_output_file::really_print_line(hunits
, vunits
, node
*n
,
1735 vunits
, vunits
, hunits
)
1738 n
->ascii_print(this);
1744 void ascii_output_file::really_begin_page(int /*pageno*/, vunits
/*page_length*/)
1746 fputs("<beginning of page>\n", fp
);
1749 ascii_output_file::ascii_output_file()
1753 /* suppress_output_file */
1755 suppress_output_file::suppress_output_file()
1759 void suppress_output_file::really_print_line(hunits
, vunits
, node
*, vunits
, vunits
, hunits
)
1763 void suppress_output_file::really_begin_page(int, vunits
)
1767 void suppress_output_file::really_transparent_char(unsigned char)
1771 /* glyphs, ligatures, kerns, discretionary breaks */
1773 class charinfo_node
: public node
{
1777 charinfo_node(charinfo
*, statem
*, int, node
* = 0);
1778 int ends_sentence();
1779 int overlaps_vertically();
1780 int overlaps_horizontally();
1783 charinfo_node::charinfo_node(charinfo
*c
, statem
*s
, int pop
, node
*x
)
1784 : node(x
, s
, pop
), ci(c
)
1788 int charinfo_node::ends_sentence()
1790 if (ci
->ends_sentence())
1792 else if (ci
->transparent())
1798 int charinfo_node::overlaps_horizontally()
1800 return ci
->overlaps_horizontally();
1803 int charinfo_node::overlaps_vertically()
1805 return ci
->overlaps_vertically();
1808 class glyph_node
: public charinfo_node
{
1809 static glyph_node
*free_list
;
1813 color
*fcol
; /* this is needed for grotty */
1816 glyph_node(charinfo
*, tfont
*, color
*, color
*, hunits
,
1817 statem
*, int, node
* = 0);
1820 void *operator new(size_t);
1821 void operator delete(void *);
1822 glyph_node(charinfo
*, tfont
*, color
*, color
*,
1823 statem
*, int, node
* = 0);
1826 node
*merge_glyph_node(glyph_node
*);
1827 node
*merge_self(node
*);
1829 node
*last_char_node();
1831 void vertical_extent(vunits
*, vunits
*);
1832 hunits
subscript_correction();
1833 hunits
italic_correction();
1834 hunits
left_italic_correction();
1836 hyphenation_type
get_hyphenation_type();
1838 color
*get_glyph_color();
1839 color
*get_fill_color();
1840 void tprint(troff_output_file
*);
1841 void zero_width_tprint(troff_output_file
*);
1842 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1843 node
*add_self(node
*, hyphen_list
**);
1844 void ascii_print(ascii_output_file
*);
1845 void asciify(macro
*);
1846 int character_type();
1854 glyph_node
*glyph_node::free_list
= 0;
1856 class ligature_node
: public glyph_node
{
1860 ligature_node(charinfo
*, tfont
*, color
*, color
*, hunits
,
1861 node
*, node
*, statem
*, int, node
* = 0);
1864 void *operator new(size_t);
1865 void operator delete(void *);
1866 ligature_node(charinfo
*, tfont
*, color
*, color
*,
1867 node
*, node
*, statem
*, int, node
* = 0);
1870 node
*add_self(node
*, hyphen_list
**);
1871 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1872 void ascii_print(ascii_output_file
*);
1873 void asciify(macro
*);
1880 class kern_pair_node
: public node
{
1885 kern_pair_node(hunits
, node
*, node
*, statem
*, int, node
* = 0);
1888 node
*merge_glyph_node(glyph_node
*);
1889 node
*add_self(node
*, hyphen_list
**);
1890 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1891 node
*add_discretionary_hyphen();
1893 node
*last_char_node();
1894 hunits
italic_correction();
1895 hunits
subscript_correction();
1896 void tprint(troff_output_file
*);
1897 hyphenation_type
get_hyphenation_type();
1898 int ends_sentence();
1899 void ascii_print(ascii_output_file
*);
1900 void asciify(macro
*);
1905 void vertical_extent(vunits
*, vunits
*);
1908 class dbreak_node
: public node
{
1913 dbreak_node(node
*, node
*, statem
*, int, node
* = 0);
1916 node
*merge_glyph_node(glyph_node
*);
1917 node
*add_discretionary_hyphen();
1919 node
*last_char_node();
1920 hunits
italic_correction();
1921 hunits
subscript_correction();
1922 void tprint(troff_output_file
*);
1923 breakpoint
*get_breakpoints(hunits width
, int ns
, breakpoint
*rest
= 0,
1926 int ends_sentence();
1927 void split(int, node
**, node
**);
1928 hyphenation_type
get_hyphenation_type();
1929 void ascii_print(ascii_output_file
*);
1930 void asciify(macro
*);
1937 void *glyph_node::operator new(size_t n
)
1939 assert(n
== sizeof(glyph_node
));
1941 const int BLOCK
= 1024;
1942 free_list
= (glyph_node
*)new char[sizeof(glyph_node
)*BLOCK
];
1943 for (int i
= 0; i
< BLOCK
- 1; i
++)
1944 free_list
[i
].next
= free_list
+ i
+ 1;
1945 free_list
[BLOCK
-1].next
= 0;
1947 glyph_node
*p
= free_list
;
1948 free_list
= (glyph_node
*)(free_list
->next
);
1953 void *ligature_node::operator new(size_t n
)
1958 void glyph_node::operator delete(void *p
)
1961 ((glyph_node
*)p
)->next
= free_list
;
1962 free_list
= (glyph_node
*)p
;
1966 void ligature_node::operator delete(void *p
)
1971 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
1972 statem
*s
, int pop
, node
*x
)
1973 : charinfo_node(c
, s
, pop
, x
), tf(t
), gcol(gc
), fcol(fc
)
1976 wid
= tf
->get_width(ci
);
1981 glyph_node::glyph_node(charinfo
*c
, tfont
*t
,
1982 color
*gc
, color
*fc
, hunits w
,
1983 statem
*s
, int pop
, node
*x
)
1984 : charinfo_node(c
, s
, pop
, x
), tf(t
), gcol(gc
), fcol(fc
), wid(w
)
1989 node
*glyph_node::copy()
1992 return new glyph_node(ci
, tf
, gcol
, fcol
, wid
, state
, div_nest_level
);
1994 return new glyph_node(ci
, tf
, gcol
, fcol
, state
, div_nest_level
);
1998 node
*glyph_node::merge_self(node
*nd
)
2000 return nd
->merge_glyph_node(this);
2003 int glyph_node::character_type()
2005 return tf
->get_character_type(ci
);
2008 node
*glyph_node::add_self(node
*n
, hyphen_list
**p
)
2010 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
2013 if (n
== 0 || (nn
= n
->merge_glyph_node(this)) == 0) {
2018 nn
= nn
->add_discretionary_hyphen();
2019 hyphen_list
*pp
= *p
;
2025 units
glyph_node::size()
2027 return tf
->get_size().to_units();
2030 hyphen_list
*glyph_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2033 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
2036 tfont
*node::get_tfont()
2041 tfont
*glyph_node::get_tfont()
2046 color
*node::get_glyph_color()
2051 color
*glyph_node::get_glyph_color()
2056 color
*node::get_fill_color()
2061 color
*glyph_node::get_fill_color()
2066 node
*node::merge_glyph_node(glyph_node
*)
2071 node
*glyph_node::merge_glyph_node(glyph_node
*gn
)
2073 if (tf
== gn
->tf
&& gcol
== gn
->gcol
&& fcol
== gn
->fcol
) {
2075 if ((lig
= tf
->get_lig(ci
, gn
->ci
)) != 0) {
2078 return new ligature_node(lig
, tf
, gcol
, fcol
, this, gn
, state
,
2079 gn
->div_nest_level
, next1
);
2082 if (tf
->get_kern(ci
, gn
->ci
, &kern
)) {
2085 return new kern_pair_node(kern
, this, gn
, state
,
2086 gn
->div_nest_level
, next1
);
2095 hunits
glyph_node::width()
2100 return tf
->get_width(ci
);
2104 node
*glyph_node::last_char_node()
2109 void glyph_node::vertical_extent(vunits
*min
, vunits
*max
)
2111 *min
= -tf
->get_char_height(ci
);
2112 *max
= tf
->get_char_depth(ci
);
2115 hunits
glyph_node::skew()
2117 return tf
->get_char_skew(ci
);
2120 hunits
glyph_node::subscript_correction()
2122 return tf
->get_subscript_correction(ci
);
2125 hunits
glyph_node::italic_correction()
2127 return tf
->get_italic_correction(ci
);
2130 hunits
glyph_node::left_italic_correction()
2132 return tf
->get_left_italic_correction(ci
);
2135 hyphenation_type
glyph_node::get_hyphenation_type()
2137 return HYPHEN_MIDDLE
;
2140 void glyph_node::ascii_print(ascii_output_file
*ascii
)
2142 unsigned char c
= ci
->get_ascii_code();
2146 ascii
->outs(ci
->nm
.contents());
2149 void glyph_node::debug_node()
2151 unsigned char c
= ci
->get_ascii_code();
2152 fprintf(stderr
, "{ %s [", type());
2154 fprintf(stderr
, "%c", c
);
2156 fprintf(stderr
, ci
->nm
.contents());
2158 fprintf(stderr
, " <push_state>");
2160 state
->display_state();
2161 fprintf(stderr
, " nest level %d", div_nest_level
);
2162 fprintf(stderr
, "]}\n");
2166 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2167 node
*gn1
, node
*gn2
, statem
*s
,
2169 : glyph_node(c
, t
, gc
, fc
, s
, pop
, x
), n1(gn1
), n2(gn2
)
2174 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2175 hunits w
, node
*gn1
, node
*gn2
, statem
*s
,
2177 : glyph_node(c
, t
, gc
, fc
, w
, s
, pop
, x
), n1(gn1
), n2(gn2
)
2182 ligature_node::~ligature_node()
2188 node
*ligature_node::copy()
2191 return new ligature_node(ci
, tf
, gcol
, fcol
, wid
, n1
->copy(), n2
->copy(),
2192 state
, div_nest_level
);
2194 return new ligature_node(ci
, tf
, gcol
, fcol
, n1
->copy(), n2
->copy(),
2195 state
, div_nest_level
);
2199 void ligature_node::ascii_print(ascii_output_file
*ascii
)
2201 n1
->ascii_print(ascii
);
2202 n2
->ascii_print(ascii
);
2205 hyphen_list
*ligature_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2207 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2208 return n1
->get_hyphen_list(hl
, count
);
2211 node
*ligature_node::add_self(node
*n
, hyphen_list
**p
)
2213 n
= n1
->add_self(n
, p
);
2214 n
= n2
->add_self(n
, p
);
2220 kern_pair_node::kern_pair_node(hunits n
, node
*first
, node
*second
,
2221 statem
* s
, int pop
, node
*x
)
2222 : node(x
, s
, pop
), amount(n
), n1(first
), n2(second
)
2226 dbreak_node::dbreak_node(node
*n
, node
*p
, statem
*s
, int pop
, node
*x
)
2227 : node(x
, s
, pop
), none(n
), pre(p
), post(0)
2231 node
*dbreak_node::merge_glyph_node(glyph_node
*gn
)
2233 glyph_node
*gn2
= (glyph_node
*)gn
->copy();
2234 node
*new_none
= none
? none
->merge_glyph_node(gn
) : 0;
2235 node
*new_post
= post
? post
->merge_glyph_node(gn2
) : 0;
2236 if (new_none
== 0 && new_post
== 0) {
2255 node
*kern_pair_node::merge_glyph_node(glyph_node
*gn
)
2257 node
*nd
= n2
->merge_glyph_node(gn
);
2261 nd
= n2
->merge_self(n1
);
2272 hunits
kern_pair_node::italic_correction()
2274 return n2
->italic_correction();
2277 hunits
kern_pair_node::subscript_correction()
2279 return n2
->subscript_correction();
2282 void kern_pair_node::vertical_extent(vunits
*min
, vunits
*max
)
2284 n1
->vertical_extent(min
, max
);
2286 n2
->vertical_extent(&min2
, &max2
);
2293 node
*kern_pair_node::add_discretionary_hyphen()
2295 tfont
*tf
= n2
->get_tfont();
2297 if (tf
->contains(soft_hyphen_char
)) {
2298 color
*gcol
= n2
->get_glyph_color();
2299 color
*fcol
= n2
->get_fill_color();
2303 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
,
2304 state
, div_nest_level
);
2305 node
*nn
= n
->merge_glyph_node(gn
);
2310 return new dbreak_node(this, nn
, state
, div_nest_level
, next1
);
2316 kern_pair_node::~kern_pair_node()
2324 dbreak_node::~dbreak_node()
2326 delete_node_list(pre
);
2327 delete_node_list(post
);
2328 delete_node_list(none
);
2331 node
*kern_pair_node::copy()
2333 return new kern_pair_node(amount
, n1
->copy(), n2
->copy(), state
,
2337 node
*copy_node_list(node
*n
)
2341 node
*nn
= n
->copy();
2355 void delete_node_list(node
*n
)
2364 node
*dbreak_node::copy()
2366 dbreak_node
*p
= new dbreak_node(copy_node_list(none
), copy_node_list(pre
),
2367 state
, div_nest_level
);
2368 p
->post
= copy_node_list(post
);
2372 hyphen_list
*node::get_hyphen_list(hyphen_list
*tail
, int *)
2377 hyphen_list
*kern_pair_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2379 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2380 return n1
->get_hyphen_list(hl
, count
);
2383 class hyphen_inhibitor_node
: public node
{
2385 hyphen_inhibitor_node(node
* = 0);
2391 hyphenation_type
get_hyphenation_type();
2394 hyphen_inhibitor_node::hyphen_inhibitor_node(node
*nd
) : node(nd
)
2398 node
*hyphen_inhibitor_node::copy()
2400 return new hyphen_inhibitor_node
;
2403 int hyphen_inhibitor_node::same(node
*)
2408 const char *hyphen_inhibitor_node::type()
2410 return "hyphen_inhibitor_node";
2413 int hyphen_inhibitor_node::force_tprint()
2418 int hyphen_inhibitor_node::is_tag()
2423 hyphenation_type
hyphen_inhibitor_node::get_hyphenation_type()
2425 return HYPHEN_INHIBIT
;
2428 /* add_discretionary_hyphen methods */
2430 node
*dbreak_node::add_discretionary_hyphen()
2433 post
= post
->add_discretionary_hyphen();
2435 none
= none
->add_discretionary_hyphen();
2439 node
*node::add_discretionary_hyphen()
2441 tfont
*tf
= get_tfont();
2443 return new hyphen_inhibitor_node(this);
2444 if (tf
->contains(soft_hyphen_char
)) {
2445 color
*gcol
= get_glyph_color();
2446 color
*fcol
= get_fill_color();
2450 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
,
2451 state
, div_nest_level
);
2452 node
*n1
= n
->merge_glyph_node(gn
);
2457 return new dbreak_node(this, n1
, state
, div_nest_level
, next1
);
2462 node
*node::merge_self(node
*)
2467 node
*node::add_self(node
*n
, hyphen_list
** /*p*/)
2473 node
*kern_pair_node::add_self(node
*n
, hyphen_list
**p
)
2475 n
= n1
->add_self(n
, p
);
2476 n
= n2
->add_self(n
, p
);
2482 hunits
node::width()
2487 node
*node::last_char_node()
2492 int node::force_tprint()
2502 hunits
hmotion_node::width()
2509 return points_to_units(10);
2512 void node::debug_node()
2514 fprintf(stderr
, "{ %s ", type());
2516 fprintf(stderr
, " <push_state>");
2518 fprintf(stderr
, " <state>");
2519 fprintf(stderr
, " nest level %d", div_nest_level
);
2520 fprintf(stderr
, " }\n");
2524 void node::debug_node_list()
2535 hunits
kern_pair_node::width()
2537 return n1
->width() + n2
->width() + amount
;
2540 node
*kern_pair_node::last_char_node()
2542 node
*nd
= n2
->last_char_node();
2545 return n1
->last_char_node();
2548 hunits
dbreak_node::width()
2551 for (node
*n
= none
; n
!= 0; n
= n
->next
)
2556 node
*dbreak_node::last_char_node()
2558 for (node
*n
= none
; n
; n
= n
->next
) {
2559 node
*last_node
= n
->last_char_node();
2566 hunits
dbreak_node::italic_correction()
2568 return none
? none
->italic_correction() : H0
;
2571 hunits
dbreak_node::subscript_correction()
2573 return none
? none
->subscript_correction() : H0
;
2576 class italic_corrected_node
: public node
{
2580 italic_corrected_node(node
*, hunits
, statem
*, int, node
* = 0);
2581 ~italic_corrected_node();
2583 void ascii_print(ascii_output_file
*);
2584 void asciify(macro
*);
2586 node
*last_char_node();
2587 void vertical_extent(vunits
*, vunits
*);
2588 int ends_sentence();
2589 int overlaps_horizontally();
2590 int overlaps_vertically();
2592 hyphenation_type
get_hyphenation_type();
2594 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2595 int character_type();
2596 void tprint(troff_output_file
*);
2597 hunits
subscript_correction();
2599 node
*add_self(node
*, hyphen_list
**);
2605 node
*node::add_italic_correction(hunits
*wd
)
2607 hunits ic
= italic_correction();
2614 return new italic_corrected_node(this, ic
, state
, div_nest_level
, next1
);
2618 italic_corrected_node::italic_corrected_node(node
*nn
, hunits xx
, statem
*s
,
2620 : node(p
, s
, pop
), n(nn
), x(xx
)
2625 italic_corrected_node::~italic_corrected_node()
2630 node
*italic_corrected_node::copy()
2632 return new italic_corrected_node(n
->copy(), x
, state
, div_nest_level
);
2635 hunits
italic_corrected_node::width()
2637 return n
->width() + x
;
2640 void italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
2642 n
->vertical_extent(min
, max
);
2645 void italic_corrected_node::tprint(troff_output_file
*out
)
2651 hunits
italic_corrected_node::skew()
2653 return n
->skew() - x
/2;
2656 hunits
italic_corrected_node::subscript_correction()
2658 return n
->subscript_correction() - x
;
2661 void italic_corrected_node::ascii_print(ascii_output_file
*out
)
2663 n
->ascii_print(out
);
2666 int italic_corrected_node::ends_sentence()
2668 return n
->ends_sentence();
2671 int italic_corrected_node::overlaps_horizontally()
2673 return n
->overlaps_horizontally();
2676 int italic_corrected_node::overlaps_vertically()
2678 return n
->overlaps_vertically();
2681 node
*italic_corrected_node::last_char_node()
2683 return n
->last_char_node();
2686 tfont
*italic_corrected_node::get_tfont()
2688 return n
->get_tfont();
2691 hyphenation_type
italic_corrected_node::get_hyphenation_type()
2693 return n
->get_hyphenation_type();
2696 node
*italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
2698 nd
= n
->add_self(nd
, p
);
2699 hunits not_interested
;
2700 nd
= nd
->add_italic_correction(¬_interested
);
2706 hyphen_list
*italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
2709 return n
->get_hyphen_list(tail
, count
);
2712 int italic_corrected_node::character_type()
2714 return n
->character_type();
2717 class break_char_node
: public node
{
2722 break_char_node(node
*, int, color
*, node
* = 0);
2723 break_char_node(node
*, int, color
*, statem
*, int, node
* = 0);
2727 vunits
vertical_width();
2728 node
*last_char_node();
2729 int character_type();
2730 int ends_sentence();
2731 node
*add_self(node
*, hyphen_list
**);
2732 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2733 void tprint(troff_output_file
*);
2734 void zero_width_tprint(troff_output_file
*);
2735 void ascii_print(ascii_output_file
*);
2736 void asciify(macro
*);
2737 hyphenation_type
get_hyphenation_type();
2738 int overlaps_vertically();
2739 int overlaps_horizontally();
2748 break_char_node::break_char_node(node
*n
, int bc
, color
*c
, node
*x
)
2749 : node(x
), ch(n
), break_code(bc
), col(c
)
2753 break_char_node::break_char_node(node
*n
, int bc
, color
*c
, statem
*s
,
2755 : node(x
, s
, pop
), ch(n
), break_code(bc
), col(c
)
2759 break_char_node::~break_char_node()
2764 node
*break_char_node::copy()
2766 return new break_char_node(ch
->copy(), break_code
, col
, state
,
2770 hunits
break_char_node::width()
2775 vunits
break_char_node::vertical_width()
2777 return ch
->vertical_width();
2780 node
*break_char_node::last_char_node()
2782 return ch
->last_char_node();
2785 int break_char_node::character_type()
2787 return ch
->character_type();
2790 int break_char_node::ends_sentence()
2792 return ch
->ends_sentence();
2795 node
*break_char_node::add_self(node
*n
, hyphen_list
**p
)
2797 assert((*p
)->hyphenation_code
== 0);
2798 if ((*p
)->breakable
&& (break_code
& 1)) {
2799 n
= new space_node(H0
, col
, n
);
2804 if ((*p
)->breakable
&& (break_code
& 2)) {
2805 n
= new space_node(H0
, col
, n
);
2808 hyphen_list
*pp
= *p
;
2814 hyphen_list
*break_char_node::get_hyphen_list(hyphen_list
*tail
, int *)
2816 return new hyphen_list(0, tail
);
2819 hyphenation_type
break_char_node::get_hyphenation_type()
2821 return HYPHEN_MIDDLE
;
2824 void break_char_node::ascii_print(ascii_output_file
*ascii
)
2826 ch
->ascii_print(ascii
);
2829 int break_char_node::overlaps_vertically()
2831 return ch
->overlaps_vertically();
2834 int break_char_node::overlaps_horizontally()
2836 return ch
->overlaps_horizontally();
2839 units
break_char_node::size()
2844 tfont
*break_char_node::get_tfont()
2846 return ch
->get_tfont();
2849 node
*extra_size_node::copy()
2851 return new extra_size_node(n
, state
, div_nest_level
);
2854 extra_size_node::extra_size_node(vunits i
, statem
*s
, int pop
)
2855 : node(0, s
, pop
), n(i
)
2859 extra_size_node::extra_size_node(vunits i
)
2864 node
*vertical_size_node::copy()
2866 return new vertical_size_node(n
, state
, div_nest_level
);
2869 vertical_size_node::vertical_size_node(vunits i
, statem
*s
, int pop
)
2870 : node(0, s
, pop
), n(i
)
2874 vertical_size_node::vertical_size_node(vunits i
)
2879 node
*hmotion_node::copy()
2881 return new hmotion_node(n
, was_tab
, unformat
, col
, state
, div_nest_level
);
2884 node
*space_char_hmotion_node::copy()
2886 return new space_char_hmotion_node(n
, col
, state
, div_nest_level
);
2889 vmotion_node::vmotion_node(vunits i
, color
*c
)
2894 vmotion_node::vmotion_node(vunits i
, color
*c
, statem
*s
, int pop
)
2895 : node(0, s
, pop
), n(i
), col(c
)
2899 node
*vmotion_node::copy()
2901 return new vmotion_node(n
, col
, state
, div_nest_level
);
2904 node
*dummy_node::copy()
2906 return new dummy_node
;
2909 node
*transparent_dummy_node::copy()
2911 return new transparent_dummy_node
;
2914 hline_node::~hline_node()
2920 hline_node::hline_node(hunits i
, node
*c
, node
*nxt
)
2921 : node(nxt
), x(i
), n(c
)
2925 hline_node::hline_node(hunits i
, node
*c
, statem
*s
, int pop
, node
*nxt
)
2926 : node(nxt
, s
, pop
), x(i
), n(c
)
2930 node
*hline_node::copy()
2932 return new hline_node(x
, n
? n
->copy() : 0, state
, div_nest_level
);
2935 hunits
hline_node::width()
2937 return x
< H0
? H0
: x
;
2940 vline_node::vline_node(vunits i
, node
*c
, node
*nxt
)
2941 : node(nxt
), x(i
), n(c
)
2945 vline_node::vline_node(vunits i
, node
*c
, statem
*s
, int pop
, node
*nxt
)
2946 : node(nxt
, s
, pop
), x(i
), n(c
)
2950 vline_node::~vline_node()
2956 node
*vline_node::copy()
2958 return new vline_node(x
, n
? n
->copy() : 0, state
, div_nest_level
);
2961 hunits
vline_node::width()
2963 return n
== 0 ? H0
: n
->width();
2966 zero_width_node::zero_width_node(node
*nd
, statem
*s
, int pop
)
2967 : node(0, s
, pop
), n(nd
)
2971 zero_width_node::zero_width_node(node
*nd
)
2976 zero_width_node::~zero_width_node()
2978 delete_node_list(n
);
2981 node
*zero_width_node::copy()
2983 return new zero_width_node(copy_node_list(n
), state
, div_nest_level
);
2986 int node_list_character_type(node
*p
)
2989 for (; p
; p
= p
->next
)
2990 t
|= p
->character_type();
2994 int zero_width_node::character_type()
2996 return node_list_character_type(n
);
2999 void node_list_vertical_extent(node
*p
, vunits
*min
, vunits
*max
)
3003 vunits cur_vpos
= V0
;
3005 for (; p
; p
= p
->next
) {
3006 p
->vertical_extent(&v1
, &v2
);
3013 cur_vpos
+= p
->vertical_width();
3017 void zero_width_node::vertical_extent(vunits
*min
, vunits
*max
)
3019 node_list_vertical_extent(n
, min
, max
);
3022 overstrike_node::overstrike_node()
3023 : list(0), max_width(H0
)
3027 overstrike_node::overstrike_node(statem
*s
, int pop
)
3028 : node(0, s
, pop
), list(0), max_width(H0
)
3032 overstrike_node::~overstrike_node()
3034 delete_node_list(list
);
3037 node
*overstrike_node::copy()
3039 overstrike_node
*on
= new overstrike_node(state
, div_nest_level
);
3040 for (node
*tem
= list
; tem
; tem
= tem
->next
)
3041 on
->overstrike(tem
->copy());
3045 void overstrike_node::overstrike(node
*n
)
3049 hunits w
= n
->width();
3053 for (p
= &list
; *p
; p
= &(*p
)->next
)
3059 hunits
overstrike_node::width()
3064 bracket_node::bracket_node()
3065 : list(0), max_width(H0
)
3069 bracket_node::bracket_node(statem
*s
, int pop
)
3070 : node(0, s
, pop
), list(0), max_width(H0
)
3074 bracket_node::~bracket_node()
3076 delete_node_list(list
);
3079 node
*bracket_node::copy()
3081 bracket_node
*on
= new bracket_node(state
, div_nest_level
);
3082 node
*last_node
= 0;
3086 for (tem
= list
; tem
; tem
= tem
->next
) {
3088 tem
->next
->last
= tem
;
3091 for (tem
= last_node
; tem
; tem
= tem
->last
)
3092 on
->bracket(tem
->copy());
3096 void bracket_node::bracket(node
*n
)
3100 hunits w
= n
->width();
3107 hunits
bracket_node::width()
3117 int node::merge_space(hunits
, hunits
, hunits
)
3123 space_node
*space_node::free_list
= 0;
3125 void *space_node::operator new(size_t n
)
3127 assert(n
== sizeof(space_node
));
3129 free_list
= (space_node
*)new char[sizeof(space_node
)*BLOCK
];
3130 for (int i
= 0; i
< BLOCK
- 1; i
++)
3131 free_list
[i
].next
= free_list
+ i
+ 1;
3132 free_list
[BLOCK
-1].next
= 0;
3134 space_node
*p
= free_list
;
3135 free_list
= (space_node
*)(free_list
->next
);
3140 inline void space_node::operator delete(void *p
)
3143 ((space_node
*)p
)->next
= free_list
;
3144 free_list
= (space_node
*)p
;
3149 space_node::space_node(hunits nn
, color
*c
, node
*p
)
3150 : node(p
, 0, 0), n(nn
), set(0), was_escape_colon(0), col(c
)
3154 space_node::space_node(hunits nn
, color
*c
, statem
*s
, int pop
, node
*p
)
3155 : node(p
, s
, pop
), n(nn
), set(0), was_escape_colon(0), col(c
)
3159 space_node::space_node(hunits nn
, int s
, int flag
, color
*c
, statem
*st
,
3161 : node(p
, st
, pop
), n(nn
), set(s
), was_escape_colon(flag
), col(c
)
3166 space_node::~space_node()
3171 node
*space_node::copy()
3173 return new space_node(n
, set
, was_escape_colon
, col
, state
, div_nest_level
);
3176 int space_node::force_tprint()
3181 int space_node::is_tag()
3186 int space_node::nspaces()
3191 int space_node::merge_space(hunits h
, hunits
, hunits
)
3197 hunits
space_node::width()
3202 void node::spread_space(int*, hunits
*)
3206 void space_node::spread_space(int *n_spaces
, hunits
*desired_space
)
3209 assert(*n_spaces
> 0);
3210 if (*n_spaces
== 1) {
3211 n
+= *desired_space
;
3212 *desired_space
= H0
;
3215 hunits extra
= *desired_space
/ *n_spaces
;
3216 *desired_space
-= extra
;
3224 void node::freeze_space()
3228 void space_node::freeze_space()
3233 void node::is_escape_colon()
3237 void space_node::is_escape_colon()
3239 was_escape_colon
= 1;
3242 diverted_space_node::diverted_space_node(vunits d
, statem
*s
, int pop
,
3244 : node(p
, s
, pop
), n(d
)
3248 diverted_space_node::diverted_space_node(vunits d
, node
*p
)
3253 node
*diverted_space_node::copy()
3255 return new diverted_space_node(n
, state
, div_nest_level
);
3258 diverted_copy_file_node::diverted_copy_file_node(symbol s
, statem
*st
,
3260 : node(p
, st
, pop
), filename(s
)
3264 diverted_copy_file_node::diverted_copy_file_node(symbol s
, node
*p
)
3265 : node(p
), filename(s
)
3269 node
*diverted_copy_file_node::copy()
3271 return new diverted_copy_file_node(filename
, state
, div_nest_level
);
3274 int node::ends_sentence()
3279 int kern_pair_node::ends_sentence()
3281 switch (n2
->ends_sentence()) {
3291 return n1
->ends_sentence();
3294 int node_list_ends_sentence(node
*n
)
3296 for (; n
!= 0; n
= n
->next
)
3297 switch (n
->ends_sentence()) {
3310 int dbreak_node::ends_sentence()
3312 return node_list_ends_sentence(none
);
3315 int node::overlaps_horizontally()
3320 int node::overlaps_vertically()
3325 int node::discardable()
3330 int space_node::discardable()
3335 vunits
node::vertical_width()
3340 vunits
vline_node::vertical_width()
3345 vunits
vmotion_node::vertical_width()
3350 int node::set_unformat_flag()
3355 int node::character_type()
3360 hunits
node::subscript_correction()
3365 hunits
node::italic_correction()
3370 hunits
node::left_italic_correction()
3380 /* vertical_extent methods */
3382 void node::vertical_extent(vunits
*min
, vunits
*max
)
3384 vunits v
= vertical_width();
3395 void vline_node::vertical_extent(vunits
*min
, vunits
*max
)
3398 node::vertical_extent(min
, max
);
3401 n
->vertical_extent(&cmin
, &cmax
);
3402 vunits h
= n
->size();
3409 // we print the first character and then move up, so
3411 // we print the last character and then move up h
3424 // we move down by h and then print the first character, so
3434 /* ascii_print methods */
3436 static void ascii_print_reverse_node_list(ascii_output_file
*ascii
, node
*n
)
3440 ascii_print_reverse_node_list(ascii
, n
->next
);
3441 n
->ascii_print(ascii
);
3444 void dbreak_node::ascii_print(ascii_output_file
*ascii
)
3446 ascii_print_reverse_node_list(ascii
, none
);
3449 void kern_pair_node::ascii_print(ascii_output_file
*ascii
)
3451 n1
->ascii_print(ascii
);
3452 n2
->ascii_print(ascii
);
3455 void node::ascii_print(ascii_output_file
*)
3459 void space_node::ascii_print(ascii_output_file
*ascii
)
3465 void hmotion_node::ascii_print(ascii_output_file
*ascii
)
3467 // this is pretty arbitrary
3468 if (n
>= points_to_units(2))
3472 void space_char_hmotion_node::ascii_print(ascii_output_file
*ascii
)
3477 /* asciify methods */
3479 void node::asciify(macro
*m
)
3484 void glyph_node::asciify(macro
*m
)
3486 unsigned char c
= ci
->get_asciify_code();
3488 c
= ci
->get_ascii_code();
3497 void kern_pair_node::asciify(macro
*m
)
3505 static void asciify_reverse_node_list(macro
*m
, node
*n
)
3509 asciify_reverse_node_list(m
, n
->next
);
3513 void dbreak_node::asciify(macro
*m
)
3515 asciify_reverse_node_list(m
, none
);
3520 void ligature_node::asciify(macro
*m
)
3528 void break_char_node::asciify(macro
*m
)
3535 void italic_corrected_node::asciify(macro
*m
)
3542 void left_italic_corrected_node::asciify(macro
*m
)
3551 void hmotion_node::asciify(macro
*m
)
3561 space_char_hmotion_node::space_char_hmotion_node(hunits i
, color
*c
,
3564 : hmotion_node(i
, c
, s
, pop
, nxt
)
3568 space_char_hmotion_node::space_char_hmotion_node(hunits i
, color
*c
,
3570 : hmotion_node(i
, c
, 0, 0, nxt
)
3574 void space_char_hmotion_node::asciify(macro
*m
)
3576 m
->append(ESCAPE_SPACE
);
3580 void space_node::asciify(macro
*m
)
3582 if (was_escape_colon
) {
3583 m
->append(ESCAPE_COLON
);
3590 void word_space_node::asciify(macro
*m
)
3592 for (width_list
*w
= orig_width
; w
; w
= w
->next
)
3597 void unbreakable_space_node::asciify(macro
*m
)
3599 m
->append(ESCAPE_TILDE
);
3603 void line_start_node::asciify(macro
*)
3608 void vertical_size_node::asciify(macro
*)
3613 breakpoint
*node::get_breakpoints(hunits
/*width*/, int /*nspaces*/,
3614 breakpoint
*rest
, int /*is_inner*/)
3624 breakpoint
*space_node::get_breakpoints(hunits wd
, int ns
,
3625 breakpoint
*rest
, int is_inner
)
3627 if (next
&& next
->discardable())
3629 breakpoint
*bp
= new breakpoint
;
3636 bp
->index
= rest
->index
+ 1;
3646 int space_node::nbreaks()
3648 if (next
&& next
->discardable())
3654 static breakpoint
*node_list_get_breakpoints(node
*p
, hunits
*widthp
,
3655 int ns
, breakpoint
*rest
)
3658 rest
= p
->get_breakpoints(*widthp
,
3660 node_list_get_breakpoints(p
->next
, widthp
, ns
,
3663 *widthp
+= p
->width();
3668 breakpoint
*dbreak_node::get_breakpoints(hunits wd
, int ns
,
3669 breakpoint
*rest
, int is_inner
)
3671 breakpoint
*bp
= new breakpoint
;
3674 for (node
*tem
= pre
; tem
!= 0; tem
= tem
->next
)
3675 bp
->width
+= tem
->width();
3680 bp
->index
= rest
->index
+ 1;
3687 return node_list_get_breakpoints(none
, &wd
, ns
, bp
);
3690 int dbreak_node::nbreaks()
3693 for (node
*tem
= none
; tem
!= 0; tem
= tem
->next
)
3694 i
+= tem
->nbreaks();
3698 void node::split(int /*where*/, node
** /*prep*/, node
** /*postp*/)
3703 void space_node::split(int where
, node
**pre
, node
**post
)
3711 static void node_list_split(node
*p
, int *wherep
, node
**prep
, node
**postp
)
3715 int nb
= p
->nbreaks();
3716 node_list_split(p
->next
, wherep
, prep
, postp
);
3721 else if (*wherep
< nb
) {
3723 p
->split(*wherep
, prep
, postp
);
3732 void dbreak_node::split(int where
, node
**prep
, node
**postp
)
3742 for (tem
= pre
; tem
->next
!= 0; tem
= tem
->next
)
3753 node_list_split(none
, &where
, prep
, postp
);
3759 hyphenation_type
node::get_hyphenation_type()
3761 return HYPHEN_BOUNDARY
;
3764 hyphenation_type
dbreak_node::get_hyphenation_type()
3766 return HYPHEN_INHIBIT
;
3769 hyphenation_type
kern_pair_node::get_hyphenation_type()
3771 return HYPHEN_MIDDLE
;
3774 hyphenation_type
dummy_node::get_hyphenation_type()
3776 return HYPHEN_MIDDLE
;
3779 hyphenation_type
transparent_dummy_node::get_hyphenation_type()
3781 return HYPHEN_MIDDLE
;
3784 hyphenation_type
hmotion_node::get_hyphenation_type()
3786 return HYPHEN_MIDDLE
;
3789 hyphenation_type
space_char_hmotion_node::get_hyphenation_type()
3791 return HYPHEN_MIDDLE
;
3794 hyphenation_type
overstrike_node::get_hyphenation_type()
3796 return HYPHEN_MIDDLE
;
3799 hyphenation_type
space_node::get_hyphenation_type()
3801 if (was_escape_colon
)
3802 return HYPHEN_MIDDLE
;
3803 return HYPHEN_BOUNDARY
;
3806 hyphenation_type
unbreakable_space_node::get_hyphenation_type()
3808 return HYPHEN_MIDDLE
;
3811 int node::interpret(macro
*)
3816 special_node::special_node(const macro
&m
, int n
)
3817 : mac(m
), no_init_string(n
)
3819 font_size fs
= curenv
->get_font_size();
3820 int char_height
= curenv
->get_char_height();
3821 int char_slant
= curenv
->get_char_slant();
3822 int fontno
= env_definite_font(curenv
);
3823 tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fontno
);
3824 if (curenv
->is_composite())
3825 tf
= tf
->get_plain();
3826 gcol
= curenv
->get_glyph_color();
3827 fcol
= curenv
->get_fill_color();
3831 special_node::special_node(const macro
&m
, tfont
*t
,
3832 color
*gc
, color
*fc
,
3835 : node(0, s
, pop
), mac(m
), tf(t
), gcol(gc
), fcol(fc
), no_init_string(n
)
3840 int special_node::same(node
*n
)
3842 return mac
== ((special_node
*)n
)->mac
3843 && tf
== ((special_node
*)n
)->tf
3844 && gcol
== ((special_node
*)n
)->gcol
3845 && fcol
== ((special_node
*)n
)->fcol
3846 && no_init_string
== ((special_node
*)n
)->no_init_string
;
3849 const char *special_node::type()
3851 return "special_node";
3854 int special_node::ends_sentence()
3859 int special_node::force_tprint()
3864 int special_node::is_tag()
3869 node
*special_node::copy()
3871 return new special_node(mac
, tf
, gcol
, fcol
, state
, div_nest_level
,
3875 void special_node::tprint_start(troff_output_file
*out
)
3877 out
->start_special(tf
, gcol
, fcol
, no_init_string
);
3880 void special_node::tprint_char(troff_output_file
*out
, unsigned char c
)
3882 out
->special_char(c
);
3885 void special_node::tprint_end(troff_output_file
*out
)
3890 tfont
*special_node::get_tfont()
3897 suppress_node::suppress_node(int on_or_off
, int issue_limits
)
3898 : is_on(on_or_off
), emit_limits(issue_limits
), filename(0), position(0),
3903 suppress_node::suppress_node(symbol f
, char p
, int id
)
3904 : is_on(2), emit_limits(0), filename(f
), position(p
), image_id(id
)
3909 suppress_node::suppress_node(int issue_limits
, int on_or_off
,
3910 symbol f
, char p
, int id
,
3912 : node(0, s
, pop
), is_on(on_or_off
), emit_limits(issue_limits
), filename(f
),
3913 position(p
), image_id(id
)
3917 int suppress_node::same(node
*n
)
3919 return ((is_on
== ((suppress_node
*)n
)->is_on
)
3920 && (emit_limits
== ((suppress_node
*)n
)->emit_limits
)
3921 && (filename
== ((suppress_node
*)n
)->filename
)
3922 && (position
== ((suppress_node
*)n
)->position
)
3923 && (image_id
== ((suppress_node
*)n
)->image_id
));
3926 const char *suppress_node::type()
3928 return "suppress_node";
3931 node
*suppress_node::copy()
3933 return new suppress_node(emit_limits
, is_on
, filename
, position
, image_id
,
3934 state
, div_nest_level
);
3939 tag_node::tag_node()
3945 tag_node::tag_node(string s
, int delay
)
3946 : tag_string(s
), delayed(delay
)
3948 is_special
= !delay
;
3951 tag_node::tag_node(string s
, statem
*st
, int pop
, int delay
)
3952 : node(0, st
, pop
), tag_string(s
), delayed(delay
)
3954 is_special
= !delay
;
3957 node
*tag_node::copy()
3959 return new tag_node(tag_string
, state
, div_nest_level
, delayed
);
3962 void tag_node::tprint(troff_output_file
*out
)
3965 out
->add_to_tag_list(tag_string
);
3967 out
->state
.add_tag(out
->fp
, tag_string
);
3970 int tag_node::same(node
*nd
)
3972 return tag_string
== ((tag_node
*)nd
)->tag_string
3973 && delayed
== ((tag_node
*)nd
)->delayed
;
3976 const char *tag_node::type()
3981 int tag_node::force_tprint()
3986 int tag_node::is_tag()
3991 int tag_node::ends_sentence()
3996 int get_reg_int(const char *p
)
3998 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
4000 if (r
&& (r
->get_value(&prev_value
)))
4001 return (int)prev_value
;
4003 warning(WARN_REG
, "number register `%1' not defined", p
);
4007 const char *get_reg_str(const char *p
)
4009 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
4011 return r
->get_string();
4013 warning(WARN_REG
, "register `%1' not defined", p
);
4017 void suppress_node::put(troff_output_file
*out
, const char *s
)
4020 while (s
[i
] != (char)0) {
4021 out
->special_char(s
[i
]);
4027 * We need to remember the start of the image and its name.
4030 static char last_position
= 0;
4031 static const char *last_image_filename
= 0;
4032 static int last_image_id
= 0;
4034 inline int min(int a
, int b
)
4036 return a
< b
? a
: b
;
4040 * tprint - if (is_on == 2)
4041 * remember current position (l, r, c, i) and filename
4047 * emit postscript bounds for image
4049 * if (suppress boolean differs from current state)
4052 * record current page
4053 * set low water mark.
4056 void suppress_node::tprint(troff_output_file
*out
)
4058 int current_page
= topdiv
->get_page_number();
4059 // firstly check to see whether this suppress node contains
4060 // an image filename & position.
4062 // remember position and filename
4063 last_position
= position
;
4064 char *tem
= (char *)last_image_filename
;
4065 last_image_filename
= strsave(filename
.contents());
4068 last_image_id
= image_id
;
4069 // printf("start of image and page = %d\n", current_page);
4072 // now check whether the suppress node requires us to issue limits.
4075 // remember that the filename will contain a %d in which the
4076 // last_image_id is placed
4077 if (last_image_filename
== (char *) 0)
4080 sprintf(name
, last_image_filename
, last_image_id
);
4082 switch (last_position
) {
4084 out
->start_special();
4085 put(out
, "devtag:.centered-image");
4088 out
->start_special();
4089 put(out
, "devtag:.right-image");
4092 out
->start_special();
4093 put(out
, "devtag:.left-image");
4101 out
->start_special();
4102 put(out
, "devtag:.auto-image ");
4107 // postscript (or other device)
4108 if (suppress_start_page
> 0 && current_page
!= suppress_start_page
)
4109 error("suppression limit registers span more than one page;\n"
4110 "image description %1 will be wrong", image_no
);
4111 // if (topdiv->get_page_number() != suppress_start_page)
4112 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
4113 // topdiv->get_page_number(), suppress_start_page);
4115 // remember that the filename will contain a %d in which the
4116 // image_no is placed
4118 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
4119 topdiv
->get_page_number(),
4120 get_reg_int("opminx"), get_reg_int("opminy"),
4121 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
4122 // page offset + line length
4123 get_reg_int(".o") + get_reg_int(".l"),
4124 name
, hresolution
, vresolution
, get_reg_str(".F"));
4131 // lastly we reset the output registers
4132 reset_output_registers();
4136 suppress_start_page
= current_page
;
4141 int suppress_node::force_tprint()
4146 int suppress_node::is_tag()
4151 hunits
suppress_node::width()
4156 /* composite_node */
4158 class composite_node
: public charinfo_node
{
4162 composite_node(node
*, charinfo
*, tfont
*, statem
*, int, node
* = 0);
4166 node
*last_char_node();
4168 void tprint(troff_output_file
*);
4169 hyphenation_type
get_hyphenation_type();
4170 void ascii_print(ascii_output_file
*);
4171 void asciify(macro
*);
4172 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
4173 node
*add_self(node
*, hyphen_list
**);
4179 void vertical_extent(vunits
*, vunits
*);
4180 vunits
vertical_width();
4183 composite_node::composite_node(node
*p
, charinfo
*c
, tfont
*t
, statem
*s
,
4185 : charinfo_node(c
, s
, pop
, x
), n(p
), tf(t
)
4189 composite_node::~composite_node()
4191 delete_node_list(n
);
4194 node
*composite_node::copy()
4196 return new composite_node(copy_node_list(n
), ci
, tf
, state
, div_nest_level
);
4199 hunits
composite_node::width()
4202 if (tf
->get_constant_space(&x
))
4205 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4208 if (tf
->get_bold(&offset
))
4210 x
+= tf
->get_track_kern();
4214 node
*composite_node::last_char_node()
4219 vunits
composite_node::vertical_width()
4222 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4223 v
+= tem
->vertical_width();
4227 units
composite_node::size()
4229 return tf
->get_size().to_units();
4232 hyphenation_type
composite_node::get_hyphenation_type()
4234 return HYPHEN_MIDDLE
;
4237 void composite_node::asciify(macro
*m
)
4239 unsigned char c
= ci
->get_asciify_code();
4241 c
= ci
->get_ascii_code();
4250 void composite_node::ascii_print(ascii_output_file
*ascii
)
4252 unsigned char c
= ci
->get_ascii_code();
4256 ascii
->outs(ci
->nm
.contents());
4260 hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
4263 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
4266 node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
4268 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
4272 nn
= nn
->add_discretionary_hyphen();
4273 hyphen_list
*pp
= *p
;
4279 tfont
*composite_node::get_tfont()
4284 node
*reverse_node_list(node
*n
)
4296 void composite_node::vertical_extent(vunits
*minimum
, vunits
*maximum
)
4298 n
= reverse_node_list(n
);
4299 node_list_vertical_extent(n
, minimum
, maximum
);
4300 n
= reverse_node_list(n
);
4303 width_list::width_list(hunits w
, hunits s
)
4304 : width(w
), sentence_width(s
), next(0)
4308 width_list::width_list(width_list
*w
)
4309 : width(w
->width
), sentence_width(w
->sentence_width
), next(0)
4313 word_space_node::word_space_node(hunits d
, color
*c
, width_list
*w
, node
*x
)
4314 : space_node(d
, c
, x
), orig_width(w
), unformat(0)
4318 word_space_node::word_space_node(hunits d
, int s
, color
*c
, width_list
*w
,
4319 int flag
, statem
*st
, int pop
, node
*x
)
4320 : space_node(d
, s
, 0, c
, st
, pop
, x
), orig_width(w
), unformat(flag
)
4324 word_space_node::~word_space_node()
4326 width_list
*w
= orig_width
;
4328 width_list
*tmp
= w
;
4334 node
*word_space_node::copy()
4336 assert(orig_width
!= 0);
4337 width_list
*w_old_curr
= orig_width
;
4338 width_list
*w_new_curr
= new width_list(w_old_curr
);
4339 width_list
*w_new
= w_new_curr
;
4340 w_old_curr
= w_old_curr
->next
;
4341 while (w_old_curr
!= 0) {
4342 w_new_curr
->next
= new width_list(w_old_curr
);
4343 w_new_curr
= w_new_curr
->next
;
4344 w_old_curr
= w_old_curr
->next
;
4346 return new word_space_node(n
, set
, col
, w_new
, unformat
, state
,
4350 int word_space_node::set_unformat_flag()
4356 void word_space_node::tprint(troff_output_file
*out
)
4358 out
->fill_color(col
);
4363 int word_space_node::merge_space(hunits h
, hunits sw
, hunits ssw
)
4366 assert(orig_width
!= 0);
4367 width_list
*w
= orig_width
;
4368 for (; w
->next
; w
= w
->next
)
4370 w
->next
= new width_list(sw
, ssw
);
4374 unbreakable_space_node::unbreakable_space_node(hunits d
, color
*c
, node
*x
)
4375 : word_space_node(d
, c
, 0, x
)
4379 unbreakable_space_node::unbreakable_space_node(hunits d
, int s
,
4380 color
*c
, statem
*st
, int pop
,
4382 : word_space_node(d
, s
, c
, 0, 0, st
, pop
, x
)
4386 node
*unbreakable_space_node::copy()
4388 return new unbreakable_space_node(n
, set
, col
, state
, div_nest_level
);
4391 int unbreakable_space_node::force_tprint()
4396 int unbreakable_space_node::is_tag()
4401 breakpoint
*unbreakable_space_node::get_breakpoints(hunits
, int,
4402 breakpoint
*rest
, int)
4407 int unbreakable_space_node::nbreaks()
4412 void unbreakable_space_node::split(int, node
**, node
**)
4417 int unbreakable_space_node::merge_space(hunits
, hunits
, hunits
)
4426 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4427 color
*gc
, color
*fc
)
4428 : npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4430 point
= new hvpair
[npoints
];
4431 for (int i
= 0; i
< npoints
; i
++)
4435 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4436 color
*gc
, color
*fc
, statem
*st
, int pop
)
4437 : node(0, st
, pop
), npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4439 point
= new hvpair
[npoints
];
4440 for (int i
= 0; i
< npoints
; i
++)
4444 int draw_node::same(node
*n
)
4446 draw_node
*nd
= (draw_node
*)n
;
4447 if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
4448 || gcol
!= nd
->gcol
|| fcol
!= nd
->fcol
)
4450 for (int i
= 0; i
< npoints
; i
++)
4451 if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
4456 const char *draw_node::type()
4461 int draw_node::force_tprint()
4466 int draw_node::is_tag()
4471 draw_node::~draw_node()
4477 hunits
draw_node::width()
4480 for (int i
= 0; i
< npoints
; i
++)
4485 vunits
draw_node::vertical_width()
4490 for (int i
= 0; i
< npoints
; i
++)
4495 node
*draw_node::copy()
4497 return new draw_node(code
, point
, npoints
, sz
, gcol
, fcol
, state
,
4501 void draw_node::tprint(troff_output_file
*out
)
4503 out
->draw(code
, point
, npoints
, sz
, gcol
, fcol
);
4506 /* tprint methods */
4508 void glyph_node::tprint(troff_output_file
*out
)
4510 tfont
*ptf
= tf
->get_plain();
4512 out
->put_char_width(ci
, ptf
, gcol
, fcol
, width(), H0
);
4515 int bold
= tf
->get_bold(&offset
);
4516 hunits w
= ptf
->get_width(ci
);
4519 int cs
= tf
->get_constant_space(&x
);
4529 k
= tf
->get_track_kern();
4531 out
->put_char(ci
, ptf
, gcol
, fcol
);
4534 out
->put_char_width(ci
, ptf
, gcol
, fcol
, w
, k
);
4538 void glyph_node::zero_width_tprint(troff_output_file
*out
)
4540 tfont
*ptf
= tf
->get_plain();
4542 int bold
= tf
->get_bold(&offset
);
4544 int cs
= tf
->get_constant_space(&x
);
4546 x
-= ptf
->get_width(ci
);
4552 out
->put_char(ci
, ptf
, gcol
, fcol
);
4555 out
->put_char(ci
, ptf
, gcol
, fcol
);
4556 out
->right(-offset
);
4562 void break_char_node::tprint(troff_output_file
*t
)
4567 void break_char_node::zero_width_tprint(troff_output_file
*t
)
4569 ch
->zero_width_tprint(t
);
4572 void hline_node::tprint(troff_output_file
*out
)
4582 hunits w
= n
->width();
4584 error("horizontal line drawing character must have positive width");
4595 out
->right(xx
- xx2
);
4598 hunits rem
= x
- w
*i
;
4600 if (n
->overlaps_horizontally()) {
4603 out
->right(rem
- w
);
4613 void vline_node::tprint(troff_output_file
*out
)
4619 vunits h
= n
->size();
4620 int overlaps
= n
->overlaps_vertically();
4625 vunits rem
= y
- i
*h
;
4627 out
->right(n
->width());
4632 n
->zero_width_tprint(out
);
4636 n
->zero_width_tprint(out
);
4645 out
->down(-h
- rem
);
4651 vunits rem
= y
- i
*h
;
4654 out
->right(n
->width());
4659 n
->zero_width_tprint(out
);
4662 n
->zero_width_tprint(out
);
4671 void zero_width_node::tprint(troff_output_file
*out
)
4676 n
->zero_width_tprint(out
);
4679 int hpos
= out
->get_hpos();
4680 int vpos
= out
->get_vpos();
4686 out
->moveto(hpos
, vpos
);
4689 void overstrike_node::tprint(troff_output_file
*out
)
4692 for (node
*tem
= list
; tem
; tem
= tem
->next
) {
4693 hunits x
= (max_width
- tem
->width())/2;
4694 out
->right(x
- pos
);
4696 tem
->zero_width_tprint(out
);
4698 out
->right(max_width
- pos
);
4701 void bracket_node::tprint(troff_output_file
*out
)
4707 for (tem
= list
; tem
; tem
= tem
->next
)
4709 vunits h
= list
->size();
4710 vunits totalh
= h
*npieces
;
4711 vunits y
= (totalh
- h
)/2;
4713 for (tem
= list
; tem
; tem
= tem
->next
) {
4714 tem
->zero_width_tprint(out
);
4717 out
->right(max_width
);
4718 out
->down(totalh
- y
);
4721 void node::tprint(troff_output_file
*)
4725 void node::zero_width_tprint(troff_output_file
*out
)
4727 int hpos
= out
->get_hpos();
4728 int vpos
= out
->get_vpos();
4730 out
->moveto(hpos
, vpos
);
4733 void space_node::tprint(troff_output_file
*out
)
4735 out
->fill_color(col
);
4739 void hmotion_node::tprint(troff_output_file
*out
)
4741 out
->fill_color(col
);
4745 void space_char_hmotion_node::tprint(troff_output_file
*out
)
4747 out
->fill_color(col
);
4749 // we emit the space width as a negative glyph index
4753 out
->put(-n
.to_units());
4759 void vmotion_node::tprint(troff_output_file
*out
)
4761 out
->fill_color(col
);
4765 void kern_pair_node::tprint(troff_output_file
*out
)
4772 static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
4776 tprint_reverse_node_list(out
, n
->next
);
4780 void dbreak_node::tprint(troff_output_file
*out
)
4782 tprint_reverse_node_list(out
, none
);
4785 void composite_node::tprint(troff_output_file
*out
)
4788 int is_bold
= tf
->get_bold(&bold_offset
);
4789 hunits track_kern
= tf
->get_track_kern();
4790 hunits constant_space
;
4791 int is_constant_spaced
= tf
->get_constant_space(&constant_space
);
4793 if (is_constant_spaced
) {
4795 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4804 int hpos
= out
->get_hpos();
4805 int vpos
= out
->get_vpos();
4806 tprint_reverse_node_list(out
, n
);
4807 out
->moveto(hpos
, vpos
);
4808 out
->right(bold_offset
);
4810 tprint_reverse_node_list(out
, n
);
4811 if (is_constant_spaced
)
4814 out
->right(track_kern
);
4817 node
*make_composite_node(charinfo
*s
, environment
*env
)
4819 int fontno
= env_definite_font(env
);
4821 error("no current font");
4824 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4825 node
*n
= charinfo_to_node_list(s
, env
);
4826 font_size fs
= env
->get_font_size();
4827 int char_height
= env
->get_char_height();
4828 int char_slant
= env
->get_char_slant();
4829 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
,
4831 if (env
->is_composite())
4832 tf
= tf
->get_plain();
4833 return new composite_node(n
, s
, tf
, 0, 0, 0);
4836 node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
4838 int fontno
= env_definite_font(env
);
4840 error("no current font");
4843 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4845 int found
= font_table
[fontno
]->contains(s
);
4847 macro
*mac
= s
->get_macro();
4848 if (mac
&& s
->is_fallback())
4849 return make_composite_node(s
, env
);
4850 if (s
->numbered()) {
4851 if (!no_error_message
)
4852 warning(WARN_CHAR
, "can't find numbered character %1",
4856 special_font_list
*sf
= font_table
[fontno
]->sf
;
4857 while (sf
!= 0 && !found
) {
4860 found
= font_table
[fn
]->contains(s
);
4864 symbol f
= font_table
[fontno
]->get_name();
4865 string
gl(f
.contents());
4867 gl
+= s
->nm
.contents();
4869 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
4870 if (ci
&& ci
->get_macro())
4871 return make_composite_node(ci
, env
);
4874 sf
= global_special_fonts
;
4875 while (sf
!= 0 && !found
) {
4878 found
= font_table
[fn
]->contains(s
);
4883 if (mac
&& s
->is_special())
4884 return make_composite_node(s
, env
);
4886 for (fn
= 0; fn
< font_table_size
; fn
++)
4888 && font_table
[fn
]->is_special()
4889 && font_table
[fn
]->contains(s
)) {
4895 if (!no_error_message
&& s
->first_time_not_found()) {
4896 unsigned char input_code
= s
->get_ascii_code();
4897 if (input_code
!= 0) {
4898 if (csgraph(input_code
))
4899 warning(WARN_CHAR
, "can't find character `%1'", input_code
);
4901 warning(WARN_CHAR
, "can't find character with input code %1",
4904 else if (s
->nm
.contents())
4905 warning(WARN_CHAR
, "can't find special character `%1'",
4911 font_size fs
= env
->get_font_size();
4912 int char_height
= env
->get_char_height();
4913 int char_slant
= env
->get_char_slant();
4914 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
4915 if (env
->is_composite())
4916 tf
= tf
->get_plain();
4917 color
*gcol
= env
->get_glyph_color();
4918 color
*fcol
= env
->get_fill_color();
4919 return new glyph_node(s
, tf
, gcol
, fcol
, 0, 0);
4922 node
*make_node(charinfo
*ci
, environment
*env
)
4924 switch (ci
->get_special_translation()) {
4925 case charinfo::TRANSLATE_SPACE
:
4926 return new space_char_hmotion_node(env
->get_space_width(),
4927 env
->get_fill_color());
4928 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4929 return new unbreakable_space_node(env
->get_space_width(),
4930 env
->get_fill_color());
4931 case charinfo::TRANSLATE_DUMMY
:
4932 return new dummy_node
;
4933 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4934 error("translation to \\% ignored in this context");
4937 charinfo
*tem
= ci
->get_translation();
4940 macro
*mac
= ci
->get_macro();
4941 if (mac
&& ci
->is_normal())
4942 return make_composite_node(ci
, env
);
4944 return make_glyph_node(ci
, env
);
4947 int character_exists(charinfo
*ci
, environment
*env
)
4949 if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
4951 charinfo
*tem
= ci
->get_translation();
4954 if (ci
->get_macro())
4956 node
*nd
= make_glyph_node(ci
, env
, 1);
4964 node
*node::add_char(charinfo
*ci
, environment
*env
,
4965 hunits
*widthp
, int *spacep
, node
**glyph_comp_np
)
4968 switch (ci
->get_special_translation()) {
4969 case charinfo::TRANSLATE_SPACE
:
4970 res
= new space_char_hmotion_node(env
->get_space_width(),
4971 env
->get_fill_color(), this);
4972 *widthp
+= res
->width();
4974 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4975 res
= new unbreakable_space_node(env
->get_space_width(),
4976 env
->get_fill_color(), this);
4977 res
->freeze_space();
4978 *widthp
+= res
->width();
4979 *spacep
+= res
->nspaces();
4981 case charinfo::TRANSLATE_DUMMY
:
4982 return new dummy_node(this);
4983 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4984 return add_discretionary_hyphen();
4986 charinfo
*tem
= ci
->get_translation();
4989 macro
*mac
= ci
->get_macro();
4990 if (mac
&& ci
->is_normal()) {
4991 res
= make_composite_node(ci
, env
);
4994 *widthp
+= res
->width();
4996 *glyph_comp_np
= res
;
5000 *glyph_comp_np
= res
;
5005 node
*gn
= make_glyph_node(ci
, env
);
5009 hunits old_width
= width();
5010 node
*p
= gn
->merge_self(this);
5012 *widthp
+= gn
->width();
5017 *widthp
+= p
->width() - old_width
;
5021 *glyph_comp_np
= res
;
5025 if (ci
->can_break_before())
5027 if (ci
->can_break_after())
5030 node
*next1
= res
->next
;
5032 res
= new break_char_node(res
, break_code
, env
->get_fill_color(), next1
);
5040 int same_node(node
*n1
, node
*n2
)
5044 return n1
->type() == n2
->type() && n1
->same(n2
);
5052 int same_node_list(node
*n1
, node
*n2
)
5055 if (n1
->type() != n2
->type() || !n1
->same(n2
))
5063 int extra_size_node::same(node
*nd
)
5065 return n
== ((extra_size_node
*)nd
)->n
;
5068 const char *extra_size_node::type()
5070 return "extra_size_node";
5073 int extra_size_node::force_tprint()
5078 int extra_size_node::is_tag()
5083 int vertical_size_node::same(node
*nd
)
5085 return n
== ((vertical_size_node
*)nd
)->n
;
5088 const char *vertical_size_node::type()
5090 return "vertical_size_node";
5093 int vertical_size_node::set_unformat_flag()
5098 int vertical_size_node::force_tprint()
5103 int vertical_size_node::is_tag()
5108 int hmotion_node::same(node
*nd
)
5110 return n
== ((hmotion_node
*)nd
)->n
5111 && col
== ((hmotion_node
*)nd
)->col
;
5114 const char *hmotion_node::type()
5116 return "hmotion_node";
5119 int hmotion_node::set_unformat_flag()
5125 int hmotion_node::force_tprint()
5130 int hmotion_node::is_tag()
5135 node
*hmotion_node::add_self(node
*nd
, hyphen_list
**p
)
5138 hyphen_list
*pp
= *p
;
5144 hyphen_list
*hmotion_node::get_hyphen_list(hyphen_list
*tail
, int *)
5146 return new hyphen_list(0, tail
);
5149 int space_char_hmotion_node::same(node
*nd
)
5151 return n
== ((space_char_hmotion_node
*)nd
)->n
5152 && col
== ((space_char_hmotion_node
*)nd
)->col
;
5155 const char *space_char_hmotion_node::type()
5157 return "space_char_hmotion_node";
5160 int space_char_hmotion_node::force_tprint()
5165 int space_char_hmotion_node::is_tag()
5170 node
*space_char_hmotion_node::add_self(node
*nd
, hyphen_list
**p
)
5173 hyphen_list
*pp
= *p
;
5179 hyphen_list
*space_char_hmotion_node::get_hyphen_list(hyphen_list
*tail
,
5182 return new hyphen_list(0, tail
);
5185 int vmotion_node::same(node
*nd
)
5187 return n
== ((vmotion_node
*)nd
)->n
5188 && col
== ((vmotion_node
*)nd
)->col
;
5191 const char *vmotion_node::type()
5193 return "vmotion_node";
5196 int vmotion_node::force_tprint()
5201 int vmotion_node::is_tag()
5206 int hline_node::same(node
*nd
)
5208 return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
5211 const char *hline_node::type()
5213 return "hline_node";
5216 int hline_node::force_tprint()
5221 int hline_node::is_tag()
5226 int vline_node::same(node
*nd
)
5228 return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
5231 const char *vline_node::type()
5233 return "vline_node";
5236 int vline_node::force_tprint()
5241 int vline_node::is_tag()
5246 int dummy_node::same(node
* /*nd*/)
5251 const char *dummy_node::type()
5253 return "dummy_node";
5256 int dummy_node::force_tprint()
5261 int dummy_node::is_tag()
5266 int transparent_dummy_node::same(node
* /*nd*/)
5271 const char *transparent_dummy_node::type()
5273 return "transparent_dummy_node";
5276 int transparent_dummy_node::force_tprint()
5281 int transparent_dummy_node::is_tag()
5286 int transparent_dummy_node::ends_sentence()
5291 int zero_width_node::same(node
*nd
)
5293 return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
5296 const char *zero_width_node::type()
5298 return "zero_width_node";
5301 int zero_width_node::force_tprint()
5306 int zero_width_node::is_tag()
5311 int italic_corrected_node::same(node
*nd
)
5313 return (x
== ((italic_corrected_node
*)nd
)->x
5314 && same_node(n
, ((italic_corrected_node
*)nd
)->n
));
5317 const char *italic_corrected_node::type()
5319 return "italic_corrected_node";
5322 int italic_corrected_node::force_tprint()
5327 int italic_corrected_node::is_tag()
5332 left_italic_corrected_node::left_italic_corrected_node(node
*xx
)
5337 left_italic_corrected_node::left_italic_corrected_node(statem
*s
, int pop
,
5339 : node(xx
, s
, pop
), n(0)
5343 left_italic_corrected_node::~left_italic_corrected_node()
5348 node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
5351 hunits lic
= gn
->left_italic_correction();
5352 if (!lic
.is_zero()) {
5359 node
*nd
= n
->merge_glyph_node(gn
);
5362 x
= n
->left_italic_correction();
5369 node
*left_italic_corrected_node::copy()
5371 left_italic_corrected_node
*nd
=
5372 new left_italic_corrected_node(state
, div_nest_level
);
5380 void left_italic_corrected_node::tprint(troff_output_file
*out
)
5388 const char *left_italic_corrected_node::type()
5390 return "left_italic_corrected_node";
5393 int left_italic_corrected_node::force_tprint()
5398 int left_italic_corrected_node::is_tag()
5403 int left_italic_corrected_node::same(node
*nd
)
5405 return (x
== ((left_italic_corrected_node
*)nd
)->x
5406 && same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
5409 void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
5412 n
->ascii_print(out
);
5415 hunits
left_italic_corrected_node::width()
5417 return n
? n
->width() + x
: H0
;
5420 void left_italic_corrected_node::vertical_extent(vunits
*minimum
,
5424 n
->vertical_extent(minimum
, maximum
);
5426 node::vertical_extent(minimum
, maximum
);
5429 hunits
left_italic_corrected_node::skew()
5431 return n
? n
->skew() + x
/2 : H0
;
5434 hunits
left_italic_corrected_node::subscript_correction()
5436 return n
? n
->subscript_correction() : H0
;
5439 hunits
left_italic_corrected_node::italic_correction()
5441 return n
? n
->italic_correction() : H0
;
5444 int left_italic_corrected_node::ends_sentence()
5446 return n
? n
->ends_sentence() : 0;
5449 int left_italic_corrected_node::overlaps_horizontally()
5451 return n
? n
->overlaps_horizontally() : 0;
5454 int left_italic_corrected_node::overlaps_vertically()
5456 return n
? n
->overlaps_vertically() : 0;
5459 node
*left_italic_corrected_node::last_char_node()
5461 return n
? n
->last_char_node() : 0;
5464 tfont
*left_italic_corrected_node::get_tfont()
5466 return n
? n
->get_tfont() : 0;
5469 hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
5472 return n
->get_hyphenation_type();
5474 return HYPHEN_MIDDLE
;
5477 hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
5480 return n
? n
->get_hyphen_list(tail
, count
) : tail
;
5483 node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
5486 nd
= new left_italic_corrected_node(state
, div_nest_level
, nd
);
5487 nd
= n
->add_self(nd
, p
);
5494 int left_italic_corrected_node::character_type()
5496 return n
? n
->character_type() : 0;
5499 int overstrike_node::same(node
*nd
)
5501 return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
5504 const char *overstrike_node::type()
5506 return "overstrike_node";
5509 int overstrike_node::force_tprint()
5514 int overstrike_node::is_tag()
5519 node
*overstrike_node::add_self(node
*n
, hyphen_list
**p
)
5522 hyphen_list
*pp
= *p
;
5528 hyphen_list
*overstrike_node::get_hyphen_list(hyphen_list
*tail
, int *)
5530 return new hyphen_list(0, tail
);
5533 int bracket_node::same(node
*nd
)
5535 return same_node_list(list
, ((bracket_node
*)nd
)->list
);
5538 const char *bracket_node::type()
5540 return "bracket_node";
5543 int bracket_node::force_tprint()
5548 int bracket_node::is_tag()
5553 int composite_node::same(node
*nd
)
5555 return ci
== ((composite_node
*)nd
)->ci
5556 && same_node_list(n
, ((composite_node
*)nd
)->n
);
5559 const char *composite_node::type()
5561 return "composite_node";
5564 int composite_node::force_tprint()
5569 int composite_node::is_tag()
5574 int glyph_node::same(node
*nd
)
5576 return ci
== ((glyph_node
*)nd
)->ci
5577 && tf
== ((glyph_node
*)nd
)->tf
5578 && gcol
== ((glyph_node
*)nd
)->gcol
5579 && fcol
== ((glyph_node
*)nd
)->fcol
;
5582 const char *glyph_node::type()
5584 return "glyph_node";
5587 int glyph_node::force_tprint()
5592 int glyph_node::is_tag()
5597 int ligature_node::same(node
*nd
)
5599 return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
5600 && same_node(n2
, ((ligature_node
*)nd
)->n2
)
5601 && glyph_node::same(nd
));
5604 const char *ligature_node::type()
5606 return "ligature_node";
5609 int ligature_node::force_tprint()
5614 int ligature_node::is_tag()
5619 int kern_pair_node::same(node
*nd
)
5621 return (amount
== ((kern_pair_node
*)nd
)->amount
5622 && same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
5623 && same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
5626 const char *kern_pair_node::type()
5628 return "kern_pair_node";
5631 int kern_pair_node::force_tprint()
5636 int kern_pair_node::is_tag()
5641 int dbreak_node::same(node
*nd
)
5643 return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
5644 && same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
5645 && same_node_list(post
, ((dbreak_node
*)nd
)->post
));
5648 const char *dbreak_node::type()
5650 return "dbreak_node";
5653 int dbreak_node::force_tprint()
5658 int dbreak_node::is_tag()
5663 int break_char_node::same(node
*nd
)
5665 return break_code
== ((break_char_node
*)nd
)->break_code
5666 && col
== ((break_char_node
*)nd
)->col
5667 && same_node(ch
, ((break_char_node
*)nd
)->ch
);
5670 const char *break_char_node::type()
5672 return "break_char_node";
5675 int break_char_node::force_tprint()
5680 int break_char_node::is_tag()
5685 int line_start_node::same(node
* /*nd*/)
5690 const char *line_start_node::type()
5692 return "line_start_node";
5695 int line_start_node::force_tprint()
5700 int line_start_node::is_tag()
5705 int space_node::same(node
*nd
)
5707 return n
== ((space_node
*)nd
)->n
5708 && set
== ((space_node
*)nd
)->set
5709 && col
== ((space_node
*)nd
)->col
;
5712 const char *space_node::type()
5714 return "space_node";
5717 int word_space_node::same(node
*nd
)
5719 return n
== ((word_space_node
*)nd
)->n
5720 && set
== ((word_space_node
*)nd
)->set
5721 && col
== ((word_space_node
*)nd
)->col
;
5724 const char *word_space_node::type()
5726 return "word_space_node";
5729 int word_space_node::force_tprint()
5734 int word_space_node::is_tag()
5739 void unbreakable_space_node::tprint(troff_output_file
*out
)
5741 out
->fill_color(col
);
5743 // we emit the space width as a negative glyph index
5747 out
->put(-n
.to_units());
5753 int unbreakable_space_node::same(node
*nd
)
5755 return n
== ((unbreakable_space_node
*)nd
)->n
5756 && set
== ((unbreakable_space_node
*)nd
)->set
5757 && col
== ((unbreakable_space_node
*)nd
)->col
;
5760 const char *unbreakable_space_node::type()
5762 return "unbreakable_space_node";
5765 node
*unbreakable_space_node::add_self(node
*nd
, hyphen_list
**p
)
5768 hyphen_list
*pp
= *p
;
5774 hyphen_list
*unbreakable_space_node::get_hyphen_list(hyphen_list
*tail
, int *)
5776 return new hyphen_list(0, tail
);
5779 int diverted_space_node::same(node
*nd
)
5781 return n
== ((diverted_space_node
*)nd
)->n
;
5784 const char *diverted_space_node::type()
5786 return "diverted_space_node";
5789 int diverted_space_node::force_tprint()
5794 int diverted_space_node::is_tag()
5799 int diverted_copy_file_node::same(node
*nd
)
5801 return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
5804 const char *diverted_copy_file_node::type()
5806 return "diverted_copy_file_node";
5809 int diverted_copy_file_node::force_tprint()
5814 int diverted_copy_file_node::is_tag()
5819 // Grow the font_table so that its size is > n.
5821 static void grow_font_table(int n
)
5823 assert(n
>= font_table_size
);
5824 font_info
**old_font_table
= font_table
;
5825 int old_font_table_size
= font_table_size
;
5826 font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
5827 if (font_table_size
<= n
)
5828 font_table_size
= n
+ 10;
5829 font_table
= new font_info
*[font_table_size
];
5830 if (old_font_table_size
)
5831 memcpy(font_table
, old_font_table
,
5832 old_font_table_size
*sizeof(font_info
*));
5833 a_delete old_font_table
;
5834 for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
5838 dictionary
font_translation_dictionary(17);
5840 static symbol
get_font_translation(symbol nm
)
5842 void *p
= font_translation_dictionary
.lookup(nm
);
5843 return p
? symbol((char *)p
) : nm
;
5846 dictionary
font_dictionary(50);
5848 static int mount_font_no_translate(int n
, symbol name
, symbol external_name
,
5852 // We store the address of this char in font_dictionary to indicate
5853 // that we've previously tried to mount the font and failed.
5856 void *p
= font_dictionary
.lookup(external_name
);
5859 fm
= font::load_font(external_name
.contents(), ¬_found
, check_only
);
5864 warning(WARN_FONT
, "can't find font `%1'", external_name
.contents());
5865 (void)font_dictionary
.lookup(external_name
, &a_char
);
5868 (void)font_dictionary
.lookup(name
, fm
);
5870 else if (p
== &a_char
) {
5872 error("invalid font `%1'", external_name
.contents());
5880 if (n
>= font_table_size
) {
5881 if (n
- font_table_size
> 1000) {
5882 error("font position too much larger than first unused position");
5887 else if (font_table
[n
] != 0)
5888 delete font_table
[n
];
5889 font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
5890 font_family::invalidate_fontno(n
);
5894 int mount_font(int n
, symbol name
, symbol external_name
)
5897 name
= get_font_translation(name
);
5898 if (external_name
.is_null())
5899 external_name
= name
;
5901 external_name
= get_font_translation(external_name
);
5902 return mount_font_no_translate(n
, name
, external_name
);
5905 int check_font(symbol fam
, symbol name
)
5907 if (check_style(name
))
5908 name
= concat(fam
, name
);
5909 return mount_font_no_translate(0, name
, name
, 1);
5912 int check_style(symbol s
)
5914 int i
= symbol_fontno(s
);
5915 return i
< 0 ? 0 : font_table
[i
]->is_style();
5918 void mount_style(int n
, symbol name
)
5921 if (n
>= font_table_size
) {
5922 if (n
- font_table_size
> 1000) {
5923 error("font position too much larger than first unused position");
5928 else if (font_table
[n
] != 0)
5929 delete font_table
[n
];
5930 font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
5931 font_family::invalidate_fontno(n
);
5934 /* global functions */
5936 void font_translate()
5938 symbol from
= get_name(1);
5939 if (!from
.is_null()) {
5940 symbol to
= get_name();
5941 if (to
.is_null() || from
== to
)
5942 font_translation_dictionary
.remove(from
);
5944 (void)font_translation_dictionary
.lookup(from
, (void *)to
.contents());
5949 void font_position()
5952 if (get_integer(&n
)) {
5954 error("negative font position");
5956 symbol internal_name
= get_name(1);
5957 if (!internal_name
.is_null()) {
5958 symbol external_name
= get_long_name();
5959 mount_font(n
, internal_name
, external_name
); // ignore error
5966 font_family::font_family(symbol s
)
5967 : map_size(10), nm(s
)
5969 map
= new int[map_size
];
5970 for (int i
= 0; i
< map_size
; i
++)
5974 font_family::~font_family()
5979 int font_family::make_definite(int i
)
5982 if (i
< map_size
&& map
[i
] >= 0)
5985 if (i
< font_table_size
&& font_table
[i
] != 0) {
5986 if (i
>= map_size
) {
5987 int old_map_size
= map_size
;
5993 map
= new int[map_size
];
5994 memcpy(map
, old_map
, old_map_size
*sizeof(int));
5996 for (int j
= old_map_size
; j
< map_size
; j
++)
5999 if (font_table
[i
]->is_style()) {
6000 symbol sty
= font_table
[i
]->get_name();
6001 symbol f
= concat(nm
, sty
);
6003 // don't use symbol_fontno, because that might return a style
6004 // and because we don't want to translate the name
6005 for (n
= 0; n
< font_table_size
; n
++)
6006 if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
6007 && !font_table
[n
]->is_style())
6009 if (n
>= font_table_size
) {
6010 n
= next_available_font_position();
6011 if (!mount_font_no_translate(n
, f
, f
))
6027 dictionary
family_dictionary(5);
6029 font_family
*lookup_family(symbol nm
)
6031 font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
6033 f
= new font_family(nm
);
6034 (void)family_dictionary
.lookup(nm
, f
);
6039 void font_family::invalidate_fontno(int n
)
6041 assert(n
>= 0 && n
< font_table_size
);
6042 dictionary_iterator
iter(family_dictionary
);
6045 while (iter
.get(&nam
, (void **)&fam
)) {
6046 int mapsize
= fam
->map_size
;
6049 for (int i
= 0; i
< mapsize
; i
++)
6050 if (fam
->map
[i
] == n
)
6058 if (get_integer(&n
)) {
6060 error("negative font position");
6062 symbol internal_name
= get_name(1);
6063 if (!internal_name
.is_null())
6064 mount_style(n
, internal_name
);
6070 static int get_fontno()
6074 if (tok
.delimiter()) {
6075 symbol s
= get_name(1);
6077 n
= symbol_fontno(s
);
6079 n
= next_available_font_position();
6080 if (!mount_font(n
, s
))
6083 return curenv
->get_family()->make_definite(n
);
6086 else if (get_integer(&n
)) {
6087 if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
6088 error("bad font number");
6090 return curenv
->get_family()->make_definite(n
);
6095 static int underline_fontno
= 2;
6097 void underline_font()
6099 int n
= get_fontno();
6101 underline_fontno
= n
;
6105 int get_underline_fontno()
6107 return underline_fontno
;
6110 void define_font_special_character()
6112 int n
= get_fontno();
6117 symbol f
= font_table
[n
]->get_name();
6118 do_define_character(CHAR_FONT_SPECIAL
, f
.contents());
6121 void remove_font_special_character()
6123 int n
= get_fontno();
6128 symbol f
= font_table
[n
]->get_name();
6129 while (!tok
.newline() && !tok
.eof()) {
6130 if (!tok
.space() && !tok
.tab()) {
6131 charinfo
*s
= tok
.get_char(1);
6132 string
gl(f
.contents());
6134 gl
+= s
->nm
.contents();
6136 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
6139 macro
*m
= ci
->set_macro(0);
6148 static void read_special_fonts(special_font_list
**sp
)
6150 special_font_list
*s
= *sp
;
6153 special_font_list
*tem
= s
;
6157 special_font_list
**p
= sp
;
6159 int i
= get_fontno();
6161 special_font_list
*tem
= new special_font_list
;
6170 void font_special_request()
6172 int n
= get_fontno();
6174 read_special_fonts(&font_table
[n
]->sf
);
6178 void special_request()
6180 read_special_fonts(&global_special_fonts
);
6184 int next_available_font_position()
6187 for (i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
6192 int symbol_fontno(symbol s
)
6194 s
= get_font_translation(s
);
6195 for (int i
= 0; i
< font_table_size
; i
++)
6196 if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
6201 int is_good_fontno(int n
)
6203 return n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0;
6206 int get_bold_fontno(int n
)
6208 if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
6210 if (font_table
[n
]->get_bold(&offset
))
6211 return offset
.to_units() + 1;
6219 hunits
env_digit_width(environment
*env
)
6221 node
*n
= make_glyph_node(charset_table
['0'], env
);
6223 hunits x
= n
->width();
6231 hunits
env_space_width(environment
*env
)
6233 int fn
= env_definite_font(env
);
6234 font_size fs
= env
->get_font_size();
6235 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6236 return scale(fs
.to_units()/3, env
->get_space_size(), 12);
6238 return font_table
[fn
]->get_space_width(fs
, env
->get_space_size());
6241 hunits
env_sentence_space_width(environment
*env
)
6243 int fn
= env_definite_font(env
);
6244 font_size fs
= env
->get_font_size();
6245 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6246 return scale(fs
.to_units()/3, env
->get_sentence_space_size(), 12);
6248 return font_table
[fn
]->get_space_width(fs
, env
->get_sentence_space_size());
6251 hunits
env_half_narrow_space_width(environment
*env
)
6253 int fn
= env_definite_font(env
);
6254 font_size fs
= env
->get_font_size();
6255 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6258 return font_table
[fn
]->get_half_narrow_space_width(fs
);
6261 hunits
env_narrow_space_width(environment
*env
)
6263 int fn
= env_definite_font(env
);
6264 font_size fs
= env
->get_font_size();
6265 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6268 return font_table
[fn
]->get_narrow_space_width(fs
);
6273 int n
= get_fontno();
6276 if (tok
.delimiter()) {
6277 int f
= get_fontno();
6280 if (has_arg() && get_number(&offset
, 'u') && offset
>= 1)
6281 font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
6283 font_table
[f
]->conditional_unbold(n
);
6288 if (get_number(&offset
, 'u') && offset
>= 1)
6289 font_table
[n
]->set_bold(hunits(offset
- 1));
6291 font_table
[n
]->unbold();
6295 font_table
[n
]->unbold();
6300 track_kerning_function::track_kerning_function() : non_zero(0)
6304 track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
6305 int max_s
, hunits max_a
)
6306 : non_zero(1), min_size(min_s
), min_amount(min_a
), max_size(max_s
),
6311 int track_kerning_function::operator==(const track_kerning_function
&tk
)
6315 && min_size
== tk
.min_size
6316 && min_amount
== tk
.min_amount
6317 && max_size
== tk
.max_size
6318 && max_amount
== tk
.max_amount
);
6320 return !tk
.non_zero
;
6323 int track_kerning_function::operator!=(const track_kerning_function
&tk
)
6326 return (!tk
.non_zero
6327 || min_size
!= tk
.min_size
6328 || min_amount
!= tk
.min_amount
6329 || max_size
!= tk
.max_size
6330 || max_amount
!= tk
.max_amount
);
6335 hunits
track_kerning_function::compute(int size
)
6338 if (max_size
<= min_size
)
6340 else if (size
<= min_size
)
6342 else if (size
>= max_size
)
6345 return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
6346 + scale(min_amount
, max_size
- size
, max_size
- min_size
));
6354 int n
= get_fontno();
6357 hunits min_a
, max_a
;
6359 && get_number(&min_s
, 'z')
6360 && get_hunits(&min_a
, 'p')
6361 && get_number(&max_s
, 'z')
6362 && get_hunits(&max_a
, 'p')) {
6363 track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
6364 font_table
[n
]->set_track_kern(tk
);
6367 track_kerning_function tk
;
6368 font_table
[n
]->set_track_kern(tk
);
6374 void constant_space()
6376 int n
= get_fontno();
6379 if (!has_arg() || !get_integer(&x
))
6380 font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
6382 if (!has_arg() || !get_number(&y
, 'z'))
6383 font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
6385 font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
6397 if (has_arg() && get_integer(&lig
) && lig
>= 0 && lig
<= 2)
6398 global_ligature_mode
= lig
;
6400 global_ligature_mode
= 1;
6407 if (has_arg() && get_integer(&k
))
6408 global_kern_mode
= k
!= 0;
6410 global_kern_mode
= 1;
6414 void set_soft_hyphen_char()
6416 soft_hyphen_char
= get_optional_char();
6417 if (!soft_hyphen_char
)
6418 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);
6424 if (suppress_output_flag
)
6425 the_output
= new suppress_output_file
;
6426 else if (ascii_output_flag
)
6427 the_output
= new ascii_output_file
;
6429 the_output
= new troff_output_file
;
6432 class next_available_font_position_reg
: public reg
{
6434 const char *get_string();
6437 const char *next_available_font_position_reg::get_string()
6439 return i_to_a(next_available_font_position());
6442 class printing_reg
: public reg
{
6444 const char *get_string();
6447 const char *printing_reg::get_string()
6450 return the_output
->is_printing() ? "1" : "0";
6455 void init_node_requests()
6457 init_request("bd", bold_font
);
6458 init_request("cs", constant_space
);
6459 init_request("fp", font_position
);
6460 init_request("fschar", define_font_special_character
);
6461 init_request("fspecial", font_special_request
);
6462 init_request("ftr", font_translate
);
6463 init_request("kern", kern_request
);
6464 init_request("lg", ligature
);
6465 init_request("rfschar", remove_font_special_character
);
6466 init_request("shc", set_soft_hyphen_char
);
6467 init_request("special", special_request
);
6468 init_request("sty", style
);
6469 init_request("tkf", track_kern
);
6470 init_request("uf", underline_font
);
6471 number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
6472 number_reg_dictionary
.define(".kern",
6473 new constant_int_reg(&global_kern_mode
));
6474 number_reg_dictionary
.define(".lg",
6475 new constant_int_reg(&global_ligature_mode
));
6476 number_reg_dictionary
.define(".P", new printing_reg
);
6477 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);