2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
28 #include "dictionary.h"
40 #include "stringclass.h"
48 #else /* not _POSIX_VERSION */
50 /* traditional Unix */
52 #define WIFEXITED(s) (((s) & 0377) == 0)
53 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
54 #define WTERMSIG(s) ((s) & 0177)
55 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
56 #define WSTOPSIG(s) (((s) >> 8) & 0377)
57 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
59 #endif /* not _POSIX_VERSION */
62 * how many boundaries of images have been written? Useful for
67 static int suppress_start_page
= 0;
71 symbol
HYPHEN_SYMBOL("hy");
73 // Character used when a hyphen is inserted at a line break.
74 static charinfo
*soft_hyphen_char
;
76 enum constant_space_type
{
78 CONSTANT_SPACE_RELATIVE
,
79 CONSTANT_SPACE_ABSOLUTE
82 struct special_font_list
{
84 special_font_list
*next
;
87 special_font_list
*global_special_fonts
;
88 static int global_ligature_mode
= 1;
89 static int global_kern_mode
= 1;
91 class track_kerning_function
{
98 track_kerning_function();
99 track_kerning_function(units
, hunits
, units
, hunits
);
100 int operator==(const track_kerning_function
&);
101 int operator!=(const track_kerning_function
&);
102 hunits
compute(int point_size
);
105 // embolden fontno when this is the current font
107 struct conditional_bold
{
108 conditional_bold
*next
;
111 conditional_bold(int, hunits
, conditional_bold
* = 0);
122 symbol internal_name
;
123 symbol external_name
;
127 track_kerning_function track_kern
;
128 constant_space_type is_constant_spaced
;
129 units constant_space
;
130 int last_ligature_mode
;
132 conditional_bold
*cond_bold_list
;
135 special_font_list
*sf
;
136 font_info(symbol nm
, int n
, symbol enm
, font
*f
);
137 int contains(charinfo
*);
138 void set_bold(hunits
);
140 void set_conditional_bold(int, hunits
);
141 void conditional_unbold(int);
142 void set_track_kern(track_kerning_function
&);
143 void set_constant_space(constant_space_type
, units
= 0);
144 int is_named(symbol
);
146 tfont
*get_tfont(font_size
, int, int, int);
147 hunits
get_space_width(font_size
, int);
148 hunits
get_narrow_space_width(font_size
);
149 hunits
get_half_narrow_space_width(font_size
);
150 int get_bold(hunits
*);
153 friend symbol
get_font_name(int, environment
*);
163 char is_constant_spaced
;
167 hunits track_kern
; // add this to the width
168 hunits constant_space_width
;
172 tfont_spec(symbol nm
, int pos
, font
*, font_size
, int, int);
173 tfont_spec(const tfont_spec
&spec
) { *this = spec
; }
175 int operator==(const tfont_spec
&);
176 friend tfont
*font_info::get_tfont(font_size fs
, int, int, int);
179 class tfont
: public tfont_spec
{
180 static tfont
*tfont_list
;
182 tfont
*plain_version
;
185 int contains(charinfo
*);
186 hunits
get_width(charinfo
*c
);
187 int get_bold(hunits
*);
188 int get_constant_space(hunits
*);
189 hunits
get_track_kern();
191 font_size
get_size();
193 charinfo
*get_lig(charinfo
*c1
, charinfo
*c2
);
194 int get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
);
195 int get_input_position();
196 int get_character_type(charinfo
*);
199 vunits
get_char_height(charinfo
*);
200 vunits
get_char_depth(charinfo
*);
201 hunits
get_char_skew(charinfo
*);
202 hunits
get_italic_correction(charinfo
*);
203 hunits
get_left_italic_correction(charinfo
*);
204 hunits
get_subscript_correction(charinfo
*);
205 friend tfont
*make_tfont(tfont_spec
&);
208 inline int env_definite_font(environment
*env
)
210 return env
->get_family()->make_definite(env
->get_font());
213 /* font_info functions */
215 static font_info
**font_table
= 0;
216 static int font_table_size
= 0;
218 font_info::font_info(symbol nm
, int n
, symbol enm
, font
*f
)
219 : last_tfont(0), number(n
), last_size(0),
220 internal_name(nm
), external_name(enm
), fm(f
),
221 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE
), last_ligature_mode(1),
222 last_kern_mode(1), cond_bold_list(0), sf(0)
226 inline int font_info::contains(charinfo
*ci
)
228 return fm
!= 0 && fm
->contains(ci
->get_index());
231 inline int font_info::is_special()
233 return fm
!= 0 && fm
->is_special();
236 inline int font_info::is_style()
241 tfont
*make_tfont(tfont_spec
&spec
)
243 for (tfont
*p
= tfont::tfont_list
; p
; p
= p
->next
)
246 return new tfont(spec
);
249 // this is the current_font, fontno is where we found the character,
250 // presumably a special font
252 tfont
*font_info::get_tfont(font_size fs
, int height
, int slant
, int fontno
)
254 if (last_tfont
== 0 || fs
!= last_size
255 || height
!= last_height
|| slant
!= last_slant
256 || global_ligature_mode
!= last_ligature_mode
257 || global_kern_mode
!= last_kern_mode
258 || fontno
!= number
) {
259 font_info
*f
= font_table
[fontno
];
260 tfont_spec
spec(f
->external_name
, f
->number
, f
->fm
, fs
, height
, slant
);
261 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
262 if (p
->fontno
== fontno
) {
264 spec
.bold_offset
= p
->offset
;
267 if (!spec
.is_bold
&& is_bold
) {
269 spec
.bold_offset
= bold_offset
;
271 spec
.track_kern
= track_kern
.compute(fs
.to_scaled_points());
272 spec
.ligature_mode
= global_ligature_mode
;
273 spec
.kern_mode
= global_kern_mode
;
274 switch (is_constant_spaced
) {
275 case CONSTANT_SPACE_NONE
:
277 case CONSTANT_SPACE_ABSOLUTE
:
278 spec
.is_constant_spaced
= 1;
279 spec
.constant_space_width
= constant_space
;
281 case CONSTANT_SPACE_RELATIVE
:
282 spec
.is_constant_spaced
= 1;
283 spec
.constant_space_width
284 = scale(constant_space
*fs
.to_scaled_points(),
291 if (fontno
!= number
)
292 return make_tfont(spec
);
293 last_tfont
= make_tfont(spec
);
295 last_height
= height
;
297 last_ligature_mode
= global_ligature_mode
;
298 last_kern_mode
= global_kern_mode
;
303 int font_info::get_bold(hunits
*res
)
313 void font_info::unbold()
321 void font_info::set_bold(hunits offset
)
323 if (!is_bold
|| offset
!= bold_offset
) {
325 bold_offset
= offset
;
330 void font_info::set_conditional_bold(int fontno
, hunits offset
)
332 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
333 if (p
->fontno
== fontno
) {
334 if (offset
!= p
->offset
) {
340 cond_bold_list
= new conditional_bold(fontno
, offset
, cond_bold_list
);
343 conditional_bold::conditional_bold(int f
, hunits h
, conditional_bold
*x
)
344 : next(x
), fontno(f
), offset(h
)
348 void font_info::conditional_unbold(int fontno
)
350 for (conditional_bold
**p
= &cond_bold_list
; *p
; p
= &(*p
)->next
)
351 if ((*p
)->fontno
== fontno
) {
352 conditional_bold
*tem
= *p
;
360 void font_info::set_constant_space(constant_space_type type
, units x
)
362 if (type
!= is_constant_spaced
363 || (type
!= CONSTANT_SPACE_NONE
&& x
!= constant_space
)) {
365 is_constant_spaced
= type
;
370 void font_info::set_track_kern(track_kerning_function
&tk
)
372 if (track_kern
!= tk
) {
378 void font_info::flush()
383 int font_info::is_named(symbol s
)
385 return internal_name
== s
;
388 symbol
font_info::get_name()
390 return internal_name
;
393 symbol
get_font_name(int fontno
, environment
*env
)
395 symbol f
= font_table
[fontno
]->get_name();
396 if (font_table
[fontno
]->is_style()) {
397 return concat(env
->get_family()->nm
, f
);
402 hunits
font_info::get_space_width(font_size fs
, int space_size
)
404 if (is_constant_spaced
== CONSTANT_SPACE_NONE
)
405 return scale(hunits(fm
->get_space_width(fs
.to_scaled_points())),
407 else if (is_constant_spaced
== CONSTANT_SPACE_ABSOLUTE
)
408 return constant_space
;
410 return scale(constant_space
*fs
.to_scaled_points(),
411 units_per_inch
, 36*72*sizescale
);
414 hunits
font_info::get_narrow_space_width(font_size fs
)
416 charinfo
*ci
= get_charinfo(symbol("|"));
417 if (fm
->contains(ci
->get_index()))
418 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
420 return hunits(fs
.to_units()/6);
423 hunits
font_info::get_half_narrow_space_width(font_size fs
)
425 charinfo
*ci
= get_charinfo(symbol("^"));
426 if (fm
->contains(ci
->get_index()))
427 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
429 return hunits(fs
.to_units()/12);
434 tfont_spec::tfont_spec(symbol nm
, int n
, font
*f
,
435 font_size s
, int h
, int sl
)
436 : name(nm
), input_position(n
), fm(f
), size(s
),
437 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
440 if (height
== size
.to_scaled_points())
444 int tfont_spec::operator==(const tfont_spec
&spec
)
448 && input_position
== spec
.input_position
450 && height
== spec
.height
451 && slant
== spec
.slant
453 ? (spec
.is_bold
&& bold_offset
== spec
.bold_offset
)
455 && track_kern
== spec
.track_kern
456 && (is_constant_spaced
457 ? (spec
.is_constant_spaced
458 && constant_space_width
== spec
.constant_space_width
)
459 : !spec
.is_constant_spaced
)
460 && ligature_mode
== spec
.ligature_mode
461 && kern_mode
== spec
.kern_mode
)
467 tfont_spec
tfont_spec::plain()
469 return tfont_spec(name
, input_position
, fm
, size
, height
, slant
);
472 hunits
tfont::get_width(charinfo
*c
)
474 if (is_constant_spaced
)
475 return constant_space_width
;
477 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
478 + track_kern
+ bold_offset
);
480 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
484 vunits
tfont::get_char_height(charinfo
*c
)
486 vunits v
= fm
->get_height(c
->get_index(), size
.to_scaled_points());
487 if (height
!= 0 && height
!= size
.to_scaled_points())
488 return scale(v
, height
, size
.to_scaled_points());
493 vunits
tfont::get_char_depth(charinfo
*c
)
495 vunits v
= fm
->get_depth(c
->get_index(), size
.to_scaled_points());
496 if (height
!= 0 && height
!= size
.to_scaled_points())
497 return scale(v
, height
, size
.to_scaled_points());
502 hunits
tfont::get_char_skew(charinfo
*c
)
504 return hunits(fm
->get_skew(c
->get_index(), size
.to_scaled_points(), slant
));
507 hunits
tfont::get_italic_correction(charinfo
*c
)
509 return hunits(fm
->get_italic_correction(c
->get_index(), size
.to_scaled_points()));
512 hunits
tfont::get_left_italic_correction(charinfo
*c
)
514 return hunits(fm
->get_left_italic_correction(c
->get_index(),
515 size
.to_scaled_points()));
518 hunits
tfont::get_subscript_correction(charinfo
*c
)
520 return hunits(fm
->get_subscript_correction(c
->get_index(),
521 size
.to_scaled_points()));
524 inline int tfont::get_input_position()
526 return input_position
;
529 inline int tfont::contains(charinfo
*ci
)
531 return fm
->contains(ci
->get_index());
534 inline int tfont::get_character_type(charinfo
*ci
)
536 return fm
->get_character_type(ci
->get_index());
539 inline int tfont::get_bold(hunits
*res
)
549 inline int tfont::get_constant_space(hunits
*res
)
551 if (is_constant_spaced
) {
552 *res
= constant_space_width
;
559 inline hunits
tfont::get_track_kern()
564 inline tfont
*tfont::get_plain()
566 return plain_version
;
569 inline font_size
tfont::get_size()
574 inline symbol
tfont::get_name()
579 inline int tfont::get_height()
584 inline int tfont::get_slant()
589 symbol
SYMBOL_ff("ff");
590 symbol
SYMBOL_fi("fi");
591 symbol
SYMBOL_fl("fl");
592 symbol
SYMBOL_Fi("Fi");
593 symbol
SYMBOL_Fl("Fl");
595 charinfo
*tfont::get_lig(charinfo
*c1
, charinfo
*c2
)
597 if (ligature_mode
== 0)
600 if (c1
->get_ascii_code() == 'f') {
601 switch (c2
->get_ascii_code()) {
603 if (fm
->has_ligature(font::LIG_ff
))
604 ci
= get_charinfo(SYMBOL_ff
);
607 if (fm
->has_ligature(font::LIG_fi
))
608 ci
= get_charinfo(SYMBOL_fi
);
611 if (fm
->has_ligature(font::LIG_fl
))
612 ci
= get_charinfo(SYMBOL_fl
);
616 else if (ligature_mode
!= 2 && c1
->nm
== SYMBOL_ff
) {
617 switch (c2
->get_ascii_code()) {
619 if (fm
->has_ligature(font::LIG_ffi
))
620 ci
= get_charinfo(SYMBOL_Fi
);
623 if (fm
->has_ligature(font::LIG_ffl
))
624 ci
= get_charinfo(SYMBOL_Fl
);
628 if (ci
!= 0 && fm
->contains(ci
->get_index()))
633 inline int tfont::get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
)
638 int n
= fm
->get_kern(c1
->get_index(),
640 size
.to_scaled_points());
650 tfont
*tfont::tfont_list
= 0;
652 tfont::tfont(tfont_spec
&spec
) : tfont_spec(spec
)
656 tfont_spec plain_spec
= plain();
658 for (p
= tfont_list
; p
; p
= p
->next
)
659 if (*p
== plain_spec
) {
664 plain_version
= new tfont(plain_spec
);
669 class real_output_file
: public output_file
{
670 #ifndef POPEN_MISSING
673 int printing
; // decision via optional page list
674 int output_on
; // \O[0] or \O[1] escape calls
675 virtual void really_transparent_char(unsigned char) = 0;
676 virtual void really_print_line(hunits x
, vunits y
, node
*n
,
677 vunits before
, vunits after
, hunits width
) = 0;
678 virtual void really_begin_page(int pageno
, vunits page_length
) = 0;
679 virtual void really_copy_file(hunits x
, vunits y
, const char *filename
);
680 virtual void really_put_filename(const char *filename
);
681 virtual void really_on();
682 virtual void really_off();
689 void transparent_char(unsigned char);
690 void print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
691 void begin_page(int pageno
, vunits page_length
);
692 void put_filename(const char *filename
);
697 void copy_file(hunits x
, vunits y
, const char *filename
);
700 class suppress_output_file
: public real_output_file
{
702 suppress_output_file();
703 void really_transparent_char(unsigned char);
704 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
705 void really_begin_page(int pageno
, vunits page_length
);
708 class ascii_output_file
: public real_output_file
{
711 void really_transparent_char(unsigned char);
712 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
713 void really_begin_page(int pageno
, vunits page_length
);
714 void outc(unsigned char c
);
715 void outs(const char *s
);
718 void ascii_output_file::outc(unsigned char c
)
723 void ascii_output_file::outs(const char *s
)
733 class troff_output_file
: public real_output_file
{
742 tfont
*current_tfont
;
743 color
*current_fill_color
;
744 color
*current_glyph_color
;
745 int current_font_number
;
746 symbol
*font_position
;
748 enum { TBUF_SIZE
= 256 };
749 char tbuf
[TBUF_SIZE
];
755 void put(unsigned char c
);
757 void put(unsigned int i
);
758 void put(const char *s
);
759 void set_font(tfont
*tf
);
763 ~troff_output_file();
764 void trailer(vunits page_length
);
765 void put_char(charinfo
*, tfont
*, color
*, color
*);
766 void put_char_width(charinfo
*, tfont
*, color
*, color
*, hunits
, hunits
);
769 void moveto(hunits
, vunits
);
770 void start_special(tfont
*, color
*, color
*, int = 0);
771 void start_special();
772 void special_char(unsigned char c
);
775 void really_transparent_char(unsigned char c
);
776 void really_print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
777 void really_begin_page(int pageno
, vunits page_length
);
778 void really_copy_file(hunits x
, vunits y
, const char *filename
);
779 void really_put_filename(const char *filename
);
782 void draw(char, hvpair
*, int, font_size
, color
*, color
*);
783 void determine_line_limits (char code
, hvpair
*point
, int npoints
);
784 void check_charinfo(tfont
*tf
, charinfo
*ci
);
785 void glyph_color(color
*c
);
786 void fill_color(color
*c
);
787 int get_hpos() { return hpos
; }
788 int get_vpos() { return vpos
; }
789 friend void space_char_hmotion_node::tprint(troff_output_file
*);
790 friend void unbreakable_space_node::tprint(troff_output_file
*);
793 static void put_string(const char *s
, FILE *fp
)
795 for (; *s
!= '\0'; ++s
)
799 inline void troff_output_file::put(char c
)
804 inline void troff_output_file::put(unsigned char c
)
809 inline void troff_output_file::put(const char *s
)
814 inline void troff_output_file::put(int i
)
816 put_string(i_to_a(i
), fp
);
819 inline void troff_output_file::put(unsigned int i
)
821 put_string(ui_to_a(i
), fp
);
824 void troff_output_file::start_special(tfont
*tf
, color
*gcol
, color
*fcol
,
836 void troff_output_file::start_special()
843 void troff_output_file::special_char(unsigned char c
)
850 void troff_output_file::end_special()
855 inline void troff_output_file::moveto(hunits h
, vunits v
)
861 void troff_output_file::really_print_line(hunits x
, vunits y
, node
*n
,
862 vunits before
, vunits after
, hunits
)
870 // This ensures that transparent throughput will have a more predictable
876 put(before
.to_units());
878 put(after
.to_units());
882 inline void troff_output_file::word_marker()
889 inline void troff_output_file::right(hunits n
)
891 hpos
+= n
.to_units();
894 inline void troff_output_file::down(vunits n
)
896 vpos
+= n
.to_units();
899 void troff_output_file::do_motion()
910 if (hpos
!= output_hpos
) {
911 units n
= hpos
- output_hpos
;
912 if (n
> 0 && n
< hpos
) {
922 if (vpos
!= output_vpos
) {
923 units n
= vpos
- output_vpos
;
924 if (n
> 0 && n
< vpos
) {
940 void troff_output_file::flush_tbuf()
956 check_output_limits(hpos
, vpos
);
957 check_output_limits(hpos
, vpos
- current_size
);
959 for (int i
= 0; i
< tbuf_len
; i
++)
965 void troff_output_file::check_charinfo(tfont
*tf
, charinfo
*ci
)
970 int height
= tf
->get_char_height(ci
).to_units();
971 int width
= tf
->get_width(ci
).to_units()
972 + tf
->get_italic_correction(ci
).to_units();
973 int depth
= tf
->get_char_depth(ci
).to_units();
974 check_output_limits(output_hpos
, output_vpos
- height
);
975 check_output_limits(output_hpos
+ width
, output_vpos
+ depth
);
978 void troff_output_file::put_char_width(charinfo
*ci
, tfont
*tf
,
979 color
*gcol
, color
*fcol
,
982 int kk
= k
.to_units();
985 hpos
+= w
.to_units() + kk
;
989 unsigned char c
= ci
->get_ascii_code();
995 check_charinfo(tf
, ci
);
996 if (ci
->numbered()) {
998 put(ci
->get_number());
1002 const char *s
= ci
->nm
.contents();
1011 hpos
+= w
.to_units() + kk
;
1013 else if (tcommand_flag
) {
1014 if (tbuf_len
> 0 && hpos
== output_hpos
&& vpos
== output_vpos
1015 && (!gcol
|| gcol
== current_glyph_color
)
1016 && (!fcol
|| fcol
== current_fill_color
)
1018 && tbuf_len
< TBUF_SIZE
) {
1019 check_charinfo(tf
, ci
);
1020 tbuf
[tbuf_len
++] = c
;
1021 output_hpos
+= w
.to_units() + kk
;
1029 check_charinfo(tf
, ci
);
1030 tbuf
[tbuf_len
++] = c
;
1031 output_hpos
+= w
.to_units() + kk
;
1037 int n
= hpos
- output_hpos
;
1038 check_charinfo(tf
, ci
);
1039 // check_output_limits(output_hpos, output_vpos);
1040 if (vpos
== output_vpos
1041 && (!gcol
|| gcol
== current_glyph_color
)
1042 && (!fcol
|| fcol
== current_fill_color
)
1043 && n
> 0 && n
< 100 && !force_motion
) {
1044 put(char(n
/10 + '0'));
1045 put(char(n
%10 + '0'));
1056 hpos
+= w
.to_units() + kk
;
1060 void troff_output_file::put_char(charinfo
*ci
, tfont
*tf
,
1061 color
*gcol
, color
*fcol
)
1067 unsigned char c
= ci
->get_ascii_code();
1073 if (ci
->numbered()) {
1075 put(ci
->get_number());
1079 const char *s
= ci
->nm
.contents();
1090 int n
= hpos
- output_hpos
;
1091 if (vpos
== output_vpos
1092 && (!gcol
|| gcol
== current_glyph_color
)
1093 && (!fcol
|| fcol
== current_fill_color
)
1094 && n
> 0 && n
< 100) {
1095 put(char(n
/10 + '0'));
1096 put(char(n
%10 + '0'));
1111 // set_font calls `flush_tbuf' if necessary.
1113 void troff_output_file::set_font(tfont
*tf
)
1115 if (current_tfont
== tf
)
1118 int n
= tf
->get_input_position();
1119 symbol nm
= tf
->get_name();
1120 if (n
>= nfont_positions
|| font_position
[n
] != nm
) {
1126 if (n
>= nfont_positions
) {
1127 int old_nfont_positions
= nfont_positions
;
1128 symbol
*old_font_position
= font_position
;
1129 nfont_positions
*= 3;
1130 nfont_positions
/= 2;
1131 if (nfont_positions
<= n
)
1132 nfont_positions
= n
+ 10;
1133 font_position
= new symbol
[nfont_positions
];
1134 memcpy(font_position
, old_font_position
,
1135 old_nfont_positions
*sizeof(symbol
));
1136 a_delete old_font_position
;
1138 font_position
[n
] = nm
;
1140 if (current_font_number
!= n
) {
1144 current_font_number
= n
;
1146 int size
= tf
->get_size().to_scaled_points();
1147 if (current_size
!= size
) {
1151 current_size
= size
;
1153 int slant
= tf
->get_slant();
1154 if (current_slant
!= slant
) {
1158 current_slant
= slant
;
1160 int height
= tf
->get_height();
1161 if (current_height
!= height
) {
1163 put(height
== 0 ? current_size
: height
);
1165 current_height
= height
;
1170 // fill_color calls `flush_tbuf' and `do_motion' if necessary.
1172 void troff_output_file::fill_color(color
*col
)
1174 if (!col
|| current_fill_color
== col
)
1176 current_fill_color
= col
;
1182 unsigned int components
[4];
1184 cs
= col
->get_components(components
);
1223 // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1225 void troff_output_file::glyph_color(color
*col
)
1227 if (!col
|| current_glyph_color
== col
)
1229 current_glyph_color
= col
;
1233 // grotty doesn't like a color command if the vertical position is zero.
1236 unsigned int components
[4];
1238 cs
= col
->get_components(components
);
1277 // determine_line_limits - works out the smallest box which will contain
1278 // the entity, code, built from the point array.
1279 void troff_output_file::determine_line_limits(char code
, hvpair
*point
,
1290 // only the h field is used when defining a circle
1291 check_output_limits(output_hpos
,
1292 output_vpos
- point
[0].h
.to_units()/2);
1293 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1294 output_vpos
+ point
[0].h
.to_units()/2);
1298 check_output_limits(output_hpos
,
1299 output_vpos
- point
[0].v
.to_units()/2);
1300 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1301 output_vpos
+ point
[0].v
.to_units()/2);
1307 check_output_limits(x
, y
);
1308 for (i
= 0; i
< npoints
; i
++) {
1309 x
+= point
[i
].h
.to_units();
1310 y
+= point
[i
].v
.to_units();
1311 check_output_limits(x
, y
);
1317 for (i
= 0; i
< npoints
; i
++) {
1318 x
+= point
[i
].h
.to_units();
1319 y
+= point
[i
].v
.to_units();
1320 check_output_limits(x
, y
);
1326 int minx
, miny
, maxx
, maxy
;
1329 p
[0] = point
[0].h
.to_units();
1330 p
[1] = point
[0].v
.to_units();
1331 p
[2] = point
[1].h
.to_units();
1332 p
[3] = point
[1].v
.to_units();
1333 if (adjust_arc_center(p
, c
)) {
1334 check_output_arc_limits(x
, y
,
1335 p
[0], p
[1], p
[2], p
[3],
1337 &minx
, &maxx
, &miny
, &maxy
);
1338 check_output_limits(minx
, miny
);
1339 check_output_limits(maxx
, maxy
);
1346 check_output_limits(x
, y
);
1347 for (i
= 0; i
< npoints
; i
++) {
1348 x
+= point
[i
].h
.to_units();
1349 y
+= point
[i
].v
.to_units();
1350 check_output_limits(x
, y
);
1356 for (i
= 0; i
< npoints
; i
++) {
1357 x
+= point
[i
].h
.to_units();
1358 y
+= point
[i
].v
.to_units();
1359 check_output_limits(x
, y
);
1364 void troff_output_file::draw(char code
, hvpair
*point
, int npoints
,
1365 font_size fsize
, color
*gcol
, color
*fcol
)
1373 int size
= fsize
.to_scaled_points();
1374 if (current_size
!= size
) {
1378 current_size
= size
;
1385 put(point
[0].h
.to_units());
1388 for (i
= 0; i
< npoints
; i
++) {
1390 put(point
[i
].h
.to_units());
1392 put(point
[i
].v
.to_units());
1394 determine_line_limits(code
, point
, npoints
);
1397 for (i
= 0; i
< npoints
; i
++)
1398 output_hpos
+= point
[i
].h
.to_units();
1401 for (i
= 0; i
< npoints
; i
++)
1402 output_vpos
+= point
[i
].v
.to_units();
1409 void troff_output_file::really_on()
1416 void troff_output_file::really_off()
1421 void troff_output_file::really_put_filename(const char *filename
)
1429 void troff_output_file::really_begin_page(int pageno
, vunits page_length
)
1433 if (page_length
> V0
) {
1435 put(page_length
.to_units());
1442 current_font_number
= -1;
1444 // current_height = 0;
1445 // current_slant = 0;
1451 for (int i
= 0; i
< nfont_positions
; i
++)
1452 font_position
[i
] = NULL_SYMBOL
;
1458 void troff_output_file::really_copy_file(hunits x
, vunits y
,
1459 const char *filename
)
1465 FILE *ifp
= include_search_path
.open_file_cautious(filename
);
1467 error("can't open `%1': %2", filename
, strerror(errno
));
1470 while ((c
= getc(ifp
)) != EOF
)
1477 current_font_number
= -1;
1478 for (int i
= 0; i
< nfont_positions
; i
++)
1479 font_position
[i
] = NULL_SYMBOL
;
1482 void troff_output_file::really_transparent_char(unsigned char c
)
1487 troff_output_file::~troff_output_file()
1489 a_delete font_position
;
1492 void troff_output_file::trailer(vunits page_length
)
1495 if (page_length
> V0
) {
1498 put(page_length
.to_units());
1504 troff_output_file::troff_output_file()
1505 : current_slant(0), current_height(0), current_fill_color(0),
1506 current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0)
1508 font_position
= new symbol
[nfont_positions
];
1513 put(units_per_inch
);
1524 output_file
*the_output
= 0;
1526 output_file::output_file()
1530 output_file::~output_file()
1534 void output_file::trailer(vunits
)
1538 void output_file::put_filename(const char *)
1542 void output_file::on()
1546 void output_file::off()
1550 real_output_file::real_output_file()
1551 : printing(0), output_on(1)
1553 #ifndef POPEN_MISSING
1555 if ((fp
= popen(pipe_command
, POPEN_WT
)) != 0) {
1559 error("pipe open failed: %1", strerror(errno
));
1562 #endif /* not POPEN_MISSING */
1566 real_output_file::~real_output_file()
1570 // To avoid looping, set fp to 0 before calling fatal().
1571 if (ferror(fp
) || fflush(fp
) < 0) {
1573 fatal("error writing output file");
1575 #ifndef POPEN_MISSING
1577 int result
= pclose(fp
);
1580 fatal("pclose failed");
1581 if (!WIFEXITED(result
))
1582 error("output process `%1' got fatal signal %2",
1584 WIFSIGNALED(result
) ? WTERMSIG(result
) : WSTOPSIG(result
));
1586 int exit_status
= WEXITSTATUS(result
);
1587 if (exit_status
!= 0)
1588 error("output process `%1' exited with status %2",
1589 pipe_command
, exit_status
);
1593 #endif /* not POPEN MISSING */
1594 if (fclose(fp
) < 0) {
1596 fatal("error closing output file");
1600 void real_output_file::flush()
1603 fatal("error writing output file");
1606 int real_output_file::is_printing()
1611 void real_output_file::begin_page(int pageno
, vunits page_length
)
1613 printing
= in_output_page_list(pageno
);
1615 really_begin_page(pageno
, page_length
);
1618 void real_output_file::copy_file(hunits x
, vunits y
, const char *filename
)
1620 if (printing
&& output_on
)
1621 really_copy_file(x
, y
, filename
);
1622 check_output_limits(x
.to_units(), y
.to_units());
1625 void real_output_file::transparent_char(unsigned char c
)
1627 if (printing
&& output_on
)
1628 really_transparent_char(c
);
1631 void real_output_file::print_line(hunits x
, vunits y
, node
*n
,
1632 vunits before
, vunits after
, hunits width
)
1635 really_print_line(x
, y
, n
, before
, after
, width
);
1636 delete_node_list(n
);
1639 void real_output_file::really_copy_file(hunits
, vunits
, const char *)
1644 void real_output_file::put_filename(const char *filename
)
1646 really_put_filename(filename
);
1649 void real_output_file::really_put_filename(const char *)
1653 void real_output_file::on()
1660 void real_output_file::off()
1666 int real_output_file::is_on()
1671 void real_output_file::really_on()
1675 void real_output_file::really_off()
1679 /* ascii_output_file */
1681 void ascii_output_file::really_transparent_char(unsigned char c
)
1686 void ascii_output_file::really_print_line(hunits
, vunits
, node
*n
,
1687 vunits
, vunits
, hunits
)
1690 n
->ascii_print(this);
1696 void ascii_output_file::really_begin_page(int /*pageno*/, vunits
/*page_length*/)
1698 fputs("<beginning of page>\n", fp
);
1701 ascii_output_file::ascii_output_file()
1705 /* suppress_output_file */
1707 suppress_output_file::suppress_output_file()
1711 void suppress_output_file::really_print_line(hunits
, vunits
, node
*, vunits
, vunits
, hunits
)
1715 void suppress_output_file::really_begin_page(int, vunits
)
1719 void suppress_output_file::really_transparent_char(unsigned char)
1723 /* glyphs, ligatures, kerns, discretionary breaks */
1725 class charinfo_node
: public node
{
1729 charinfo_node(charinfo
*, node
* = 0);
1730 int ends_sentence();
1731 int overlaps_vertically();
1732 int overlaps_horizontally();
1735 charinfo_node::charinfo_node(charinfo
*c
, node
*x
)
1740 int charinfo_node::ends_sentence()
1742 if (ci
->ends_sentence())
1744 else if (ci
->transparent())
1750 int charinfo_node::overlaps_horizontally()
1752 return ci
->overlaps_horizontally();
1755 int charinfo_node::overlaps_vertically()
1757 return ci
->overlaps_vertically();
1760 class glyph_node
: public charinfo_node
{
1761 static glyph_node
*free_list
;
1765 color
*fcol
; /* this is needed for grotty */
1768 glyph_node(charinfo
*, tfont
*, color
*, color
*, hunits
, node
* = 0);
1771 void *operator new(size_t);
1772 void operator delete(void *);
1773 glyph_node(charinfo
*, tfont
*, color
*, color
*, node
* = 0);
1776 node
*merge_glyph_node(glyph_node
*);
1777 node
*merge_self(node
*);
1779 node
*last_char_node();
1781 void vertical_extent(vunits
*, vunits
*);
1782 hunits
subscript_correction();
1783 hunits
italic_correction();
1784 hunits
left_italic_correction();
1786 hyphenation_type
get_hyphenation_type();
1788 color
*get_glyph_color();
1789 color
*get_fill_color();
1790 void tprint(troff_output_file
*);
1791 void zero_width_tprint(troff_output_file
*);
1792 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1793 node
*add_self(node
*, hyphen_list
**);
1794 void ascii_print(ascii_output_file
*);
1795 void asciify(macro
*);
1796 int character_type();
1802 glyph_node
*glyph_node::free_list
= 0;
1804 class ligature_node
: public glyph_node
{
1808 ligature_node(charinfo
*, tfont
*, color
*, color
*, hunits
,
1809 node
*, node
*, node
* = 0);
1812 void *operator new(size_t);
1813 void operator delete(void *);
1814 ligature_node(charinfo
*, tfont
*, color
*, color
*,
1815 node
*, node
*, node
* = 0);
1818 node
*add_self(node
*, hyphen_list
**);
1819 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1820 void ascii_print(ascii_output_file
*);
1821 void asciify(macro
*);
1827 class kern_pair_node
: public node
{
1832 kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
= 0);
1835 node
*merge_glyph_node(glyph_node
*);
1836 node
*add_self(node
*, hyphen_list
**);
1837 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1838 node
*add_discretionary_hyphen();
1840 node
*last_char_node();
1841 hunits
italic_correction();
1842 hunits
subscript_correction();
1843 void tprint(troff_output_file
*);
1844 hyphenation_type
get_hyphenation_type();
1845 int ends_sentence();
1846 void ascii_print(ascii_output_file
*);
1847 void asciify(macro
*);
1851 void vertical_extent(vunits
*, vunits
*);
1854 class dbreak_node
: public node
{
1859 dbreak_node(node
*n
, node
*p
, node
*x
= 0);
1862 node
*merge_glyph_node(glyph_node
*);
1863 node
*add_discretionary_hyphen();
1865 node
*last_char_node();
1866 hunits
italic_correction();
1867 hunits
subscript_correction();
1868 void tprint(troff_output_file
*);
1869 breakpoint
*get_breakpoints(hunits width
, int ns
, breakpoint
*rest
= 0,
1872 int ends_sentence();
1873 void split(int, node
**, node
**);
1874 hyphenation_type
get_hyphenation_type();
1875 void ascii_print(ascii_output_file
*);
1876 void asciify(macro
*);
1882 void *glyph_node::operator new(size_t n
)
1884 assert(n
== sizeof(glyph_node
));
1886 const int BLOCK
= 1024;
1887 free_list
= (glyph_node
*)new char[sizeof(glyph_node
)*BLOCK
];
1888 for (int i
= 0; i
< BLOCK
- 1; i
++)
1889 free_list
[i
].next
= free_list
+ i
+ 1;
1890 free_list
[BLOCK
-1].next
= 0;
1892 glyph_node
*p
= free_list
;
1893 free_list
= (glyph_node
*)(free_list
->next
);
1898 void *ligature_node::operator new(size_t n
)
1903 void glyph_node::operator delete(void *p
)
1906 ((glyph_node
*)p
)->next
= free_list
;
1907 free_list
= (glyph_node
*)p
;
1911 void ligature_node::operator delete(void *p
)
1916 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
, node
*x
)
1917 : charinfo_node(c
, x
), tf(t
), gcol(gc
), fcol(fc
)
1920 wid
= tf
->get_width(ci
);
1925 glyph_node::glyph_node(charinfo
*c
, tfont
*t
,
1926 color
*gc
, color
*fc
, hunits w
, node
*x
)
1927 : charinfo_node(c
, x
), tf(t
), gcol(gc
), fcol(fc
), wid(w
)
1932 node
*glyph_node::copy()
1935 return new glyph_node(ci
, tf
, gcol
, fcol
, wid
);
1937 return new glyph_node(ci
, tf
, gcol
, fcol
);
1941 node
*glyph_node::merge_self(node
*nd
)
1943 return nd
->merge_glyph_node(this);
1946 int glyph_node::character_type()
1948 return tf
->get_character_type(ci
);
1951 node
*glyph_node::add_self(node
*n
, hyphen_list
**p
)
1953 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
1956 if (n
== 0 || (nn
= n
->merge_glyph_node(this)) == 0) {
1961 nn
= nn
->add_discretionary_hyphen();
1962 hyphen_list
*pp
= *p
;
1968 units
glyph_node::size()
1970 return tf
->get_size().to_units();
1973 hyphen_list
*glyph_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
1976 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
1979 tfont
*node::get_tfont()
1984 tfont
*glyph_node::get_tfont()
1989 color
*node::get_glyph_color()
1994 color
*glyph_node::get_glyph_color()
1999 color
*node::get_fill_color()
2004 color
*glyph_node::get_fill_color()
2009 node
*node::merge_glyph_node(glyph_node
*)
2014 node
*glyph_node::merge_glyph_node(glyph_node
*gn
)
2016 if (tf
== gn
->tf
&& gcol
== gn
->gcol
&& fcol
== gn
->fcol
) {
2018 if ((lig
= tf
->get_lig(ci
, gn
->ci
)) != 0) {
2021 return new ligature_node(lig
, tf
, gcol
, fcol
, this, gn
, next1
);
2024 if (tf
->get_kern(ci
, gn
->ci
, &kern
)) {
2027 return new kern_pair_node(kern
, this, gn
, next1
);
2036 hunits
glyph_node::width()
2041 return tf
->get_width(ci
);
2045 node
*glyph_node::last_char_node()
2050 void glyph_node::vertical_extent(vunits
*min
, vunits
*max
)
2052 *min
= -tf
->get_char_height(ci
);
2053 *max
= tf
->get_char_depth(ci
);
2056 hunits
glyph_node::skew()
2058 return tf
->get_char_skew(ci
);
2061 hunits
glyph_node::subscript_correction()
2063 return tf
->get_subscript_correction(ci
);
2066 hunits
glyph_node::italic_correction()
2068 return tf
->get_italic_correction(ci
);
2071 hunits
glyph_node::left_italic_correction()
2073 return tf
->get_left_italic_correction(ci
);
2076 hyphenation_type
glyph_node::get_hyphenation_type()
2078 return HYPHEN_MIDDLE
;
2081 void glyph_node::ascii_print(ascii_output_file
*ascii
)
2083 unsigned char c
= ci
->get_ascii_code();
2087 ascii
->outs(ci
->nm
.contents());
2090 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2091 node
*gn1
, node
*gn2
, node
*x
)
2092 : glyph_node(c
, t
, gc
, fc
, x
), n1(gn1
), n2(gn2
)
2097 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2098 hunits w
, node
*gn1
, node
*gn2
, node
*x
)
2099 : glyph_node(c
, t
, gc
, fc
, w
, x
), n1(gn1
), n2(gn2
)
2104 ligature_node::~ligature_node()
2110 node
*ligature_node::copy()
2113 return new ligature_node(ci
, tf
, gcol
, fcol
, wid
, n1
->copy(), n2
->copy());
2115 return new ligature_node(ci
, tf
, gcol
, fcol
, n1
->copy(), n2
->copy());
2119 void ligature_node::ascii_print(ascii_output_file
*ascii
)
2121 n1
->ascii_print(ascii
);
2122 n2
->ascii_print(ascii
);
2125 hyphen_list
*ligature_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2127 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2128 return n1
->get_hyphen_list(hl
, count
);
2131 node
*ligature_node::add_self(node
*n
, hyphen_list
**p
)
2133 n
= n1
->add_self(n
, p
);
2134 n
= n2
->add_self(n
, p
);
2140 kern_pair_node::kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
)
2141 : node(x
), amount(n
), n1(first
), n2(second
)
2145 dbreak_node::dbreak_node(node
*n
, node
*p
, node
*x
)
2146 : node(x
), none(n
), pre(p
), post(0)
2150 node
*dbreak_node::merge_glyph_node(glyph_node
*gn
)
2152 glyph_node
*gn2
= (glyph_node
*)gn
->copy();
2153 node
*new_none
= none
? none
->merge_glyph_node(gn
) : 0;
2154 node
*new_post
= post
? post
->merge_glyph_node(gn2
) : 0;
2155 if (new_none
== 0 && new_post
== 0) {
2174 node
*kern_pair_node::merge_glyph_node(glyph_node
*gn
)
2176 node
*nd
= n2
->merge_glyph_node(gn
);
2180 nd
= n2
->merge_self(n1
);
2191 hunits
kern_pair_node::italic_correction()
2193 return n2
->italic_correction();
2196 hunits
kern_pair_node::subscript_correction()
2198 return n2
->subscript_correction();
2201 void kern_pair_node::vertical_extent(vunits
*min
, vunits
*max
)
2203 n1
->vertical_extent(min
, max
);
2205 n2
->vertical_extent(&min2
, &max2
);
2212 node
*kern_pair_node::add_discretionary_hyphen()
2214 tfont
*tf
= n2
->get_tfont();
2216 if (tf
->contains(soft_hyphen_char
)) {
2217 color
*gcol
= n2
->get_glyph_color();
2218 color
*fcol
= n2
->get_fill_color();
2222 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
);
2223 node
*nn
= n
->merge_glyph_node(gn
);
2228 return new dbreak_node(this, nn
, next1
);
2234 kern_pair_node::~kern_pair_node()
2242 dbreak_node::~dbreak_node()
2244 delete_node_list(pre
);
2245 delete_node_list(post
);
2246 delete_node_list(none
);
2249 node
*kern_pair_node::copy()
2251 return new kern_pair_node(amount
, n1
->copy(), n2
->copy());
2254 node
*copy_node_list(node
*n
)
2258 node
*nn
= n
->copy();
2272 void delete_node_list(node
*n
)
2281 node
*dbreak_node::copy()
2283 dbreak_node
*p
= new dbreak_node(copy_node_list(none
), copy_node_list(pre
));
2284 p
->post
= copy_node_list(post
);
2288 hyphen_list
*node::get_hyphen_list(hyphen_list
*tail
, int *)
2293 hyphen_list
*kern_pair_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2295 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2296 return n1
->get_hyphen_list(hl
, count
);
2299 class hyphen_inhibitor_node
: public node
{
2301 hyphen_inhibitor_node(node
*nd
= 0);
2306 hyphenation_type
get_hyphenation_type();
2309 hyphen_inhibitor_node::hyphen_inhibitor_node(node
*nd
) : node(nd
)
2313 node
*hyphen_inhibitor_node::copy()
2315 return new hyphen_inhibitor_node
;
2318 int hyphen_inhibitor_node::same(node
*)
2323 const char *hyphen_inhibitor_node::type()
2325 return "hyphen_inhibitor_node";
2328 int hyphen_inhibitor_node::force_tprint()
2333 hyphenation_type
hyphen_inhibitor_node::get_hyphenation_type()
2335 return HYPHEN_INHIBIT
;
2338 /* add_discretionary_hyphen methods */
2340 node
*dbreak_node::add_discretionary_hyphen()
2343 post
= post
->add_discretionary_hyphen();
2345 none
= none
->add_discretionary_hyphen();
2349 node
*node::add_discretionary_hyphen()
2351 tfont
*tf
= get_tfont();
2353 return new hyphen_inhibitor_node(this);
2354 if (tf
->contains(soft_hyphen_char
)) {
2355 color
*gcol
= get_glyph_color();
2356 color
*fcol
= get_fill_color();
2360 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
);
2361 node
*n1
= n
->merge_glyph_node(gn
);
2366 return new dbreak_node(this, n1
, next1
);
2371 node
*node::merge_self(node
*)
2376 node
*node::add_self(node
*n
, hyphen_list
** /*p*/)
2382 node
*kern_pair_node::add_self(node
*n
, hyphen_list
**p
)
2384 n
= n1
->add_self(n
, p
);
2385 n
= n2
->add_self(n
, p
);
2391 hunits
node::width()
2396 node
*node::last_char_node()
2401 int node::force_tprint()
2406 hunits
hmotion_node::width()
2413 return points_to_units(10);
2416 hunits
kern_pair_node::width()
2418 return n1
->width() + n2
->width() + amount
;
2421 node
*kern_pair_node::last_char_node()
2423 node
*nd
= n2
->last_char_node();
2426 return n1
->last_char_node();
2429 hunits
dbreak_node::width()
2432 for (node
*n
= none
; n
!= 0; n
= n
->next
)
2437 node
*dbreak_node::last_char_node()
2439 for (node
*n
= none
; n
; n
= n
->next
) {
2440 node
*last
= n
->last_char_node();
2447 hunits
dbreak_node::italic_correction()
2449 return none
? none
->italic_correction() : H0
;
2452 hunits
dbreak_node::subscript_correction()
2454 return none
? none
->subscript_correction() : H0
;
2457 class italic_corrected_node
: public node
{
2461 italic_corrected_node(node
*, hunits
, node
* = 0);
2462 ~italic_corrected_node();
2464 void ascii_print(ascii_output_file
*);
2465 void asciify(macro
*);
2467 node
*last_char_node();
2468 void vertical_extent(vunits
*, vunits
*);
2469 int ends_sentence();
2470 int overlaps_horizontally();
2471 int overlaps_vertically();
2473 hyphenation_type
get_hyphenation_type();
2475 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2476 int character_type();
2477 void tprint(troff_output_file
*);
2478 hunits
subscript_correction();
2480 node
*add_self(node
*, hyphen_list
**);
2485 node
*node::add_italic_correction(hunits
*width
)
2487 hunits ic
= italic_correction();
2494 return new italic_corrected_node(this, ic
, next1
);
2498 italic_corrected_node::italic_corrected_node(node
*nn
, hunits xx
, node
*p
)
2499 : node(p
), n(nn
), x(xx
)
2504 italic_corrected_node::~italic_corrected_node()
2509 node
*italic_corrected_node::copy()
2511 return new italic_corrected_node(n
->copy(), x
);
2514 hunits
italic_corrected_node::width()
2516 return n
->width() + x
;
2519 void italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
2521 n
->vertical_extent(min
, max
);
2524 void italic_corrected_node::tprint(troff_output_file
*out
)
2530 hunits
italic_corrected_node::skew()
2532 return n
->skew() - x
/2;
2535 hunits
italic_corrected_node::subscript_correction()
2537 return n
->subscript_correction() - x
;
2540 void italic_corrected_node::ascii_print(ascii_output_file
*out
)
2542 n
->ascii_print(out
);
2545 int italic_corrected_node::ends_sentence()
2547 return n
->ends_sentence();
2550 int italic_corrected_node::overlaps_horizontally()
2552 return n
->overlaps_horizontally();
2555 int italic_corrected_node::overlaps_vertically()
2557 return n
->overlaps_vertically();
2560 node
*italic_corrected_node::last_char_node()
2562 return n
->last_char_node();
2565 tfont
*italic_corrected_node::get_tfont()
2567 return n
->get_tfont();
2570 hyphenation_type
italic_corrected_node::get_hyphenation_type()
2572 return n
->get_hyphenation_type();
2575 node
*italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
2577 nd
= n
->add_self(nd
, p
);
2578 hunits not_interested
;
2579 nd
= nd
->add_italic_correction(¬_interested
);
2585 hyphen_list
*italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
2588 return n
->get_hyphen_list(tail
, count
);
2591 int italic_corrected_node::character_type()
2593 return n
->character_type();
2596 class break_char_node
: public node
{
2601 break_char_node(node
*, int, color
*, node
* = 0);
2605 vunits
vertical_width();
2606 node
*last_char_node();
2607 int character_type();
2608 int ends_sentence();
2609 node
*add_self(node
*, hyphen_list
**);
2610 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2611 void tprint(troff_output_file
*);
2612 void zero_width_tprint(troff_output_file
*);
2613 void ascii_print(ascii_output_file
*);
2614 void asciify(macro
*);
2615 hyphenation_type
get_hyphenation_type();
2616 int overlaps_vertically();
2617 int overlaps_horizontally();
2625 break_char_node::break_char_node(node
*n
, int bc
, color
*c
, node
*x
)
2626 : node(x
), ch(n
), break_code(bc
), col(c
)
2630 break_char_node::~break_char_node()
2635 node
*break_char_node::copy()
2637 return new break_char_node(ch
->copy(), break_code
, col
);
2640 hunits
break_char_node::width()
2645 vunits
break_char_node::vertical_width()
2647 return ch
->vertical_width();
2650 node
*break_char_node::last_char_node()
2652 return ch
->last_char_node();
2655 int break_char_node::character_type()
2657 return ch
->character_type();
2660 int break_char_node::ends_sentence()
2662 return ch
->ends_sentence();
2665 node
*break_char_node::add_self(node
*n
, hyphen_list
**p
)
2667 assert((*p
)->hyphenation_code
== 0);
2668 if ((*p
)->breakable
&& (break_code
& 1)) {
2669 n
= new space_node(H0
, col
, n
);
2674 if ((*p
)->breakable
&& (break_code
& 2)) {
2675 n
= new space_node(H0
, col
, n
);
2678 hyphen_list
*pp
= *p
;
2684 hyphen_list
*break_char_node::get_hyphen_list(hyphen_list
*tail
, int *)
2686 return new hyphen_list(0, tail
);
2689 hyphenation_type
break_char_node::get_hyphenation_type()
2691 return HYPHEN_MIDDLE
;
2694 void break_char_node::ascii_print(ascii_output_file
*ascii
)
2696 ch
->ascii_print(ascii
);
2699 int break_char_node::overlaps_vertically()
2701 return ch
->overlaps_vertically();
2704 int break_char_node::overlaps_horizontally()
2706 return ch
->overlaps_horizontally();
2709 units
break_char_node::size()
2714 tfont
*break_char_node::get_tfont()
2716 return ch
->get_tfont();
2719 node
*extra_size_node::copy()
2721 return new extra_size_node(n
);
2724 node
*vertical_size_node::copy()
2726 return new vertical_size_node(n
);
2729 node
*hmotion_node::copy()
2731 return new hmotion_node(n
, was_tab
, unformat
, col
);
2734 node
*space_char_hmotion_node::copy()
2736 return new space_char_hmotion_node(n
, col
);
2739 node
*vmotion_node::copy()
2741 return new vmotion_node(n
, col
);
2744 node
*dummy_node::copy()
2746 return new dummy_node
;
2749 node
*transparent_dummy_node::copy()
2751 return new transparent_dummy_node
;
2754 hline_node::~hline_node()
2760 node
*hline_node::copy()
2762 return new hline_node(x
, n
? n
->copy() : 0);
2765 hunits
hline_node::width()
2767 return x
< H0
? H0
: x
;
2770 vline_node::~vline_node()
2776 node
*vline_node::copy()
2778 return new vline_node(x
, n
? n
->copy() : 0);
2781 hunits
vline_node::width()
2783 return n
== 0 ? H0
: n
->width();
2786 zero_width_node::zero_width_node(node
*nd
) : n(nd
)
2790 zero_width_node::~zero_width_node()
2792 delete_node_list(n
);
2795 node
*zero_width_node::copy()
2797 return new zero_width_node(copy_node_list(n
));
2800 int node_list_character_type(node
*p
)
2803 for (; p
; p
= p
->next
)
2804 t
|= p
->character_type();
2808 int zero_width_node::character_type()
2810 return node_list_character_type(n
);
2813 void node_list_vertical_extent(node
*p
, vunits
*min
, vunits
*max
)
2817 vunits cur_vpos
= V0
;
2819 for (; p
; p
= p
->next
) {
2820 p
->vertical_extent(&v1
, &v2
);
2827 cur_vpos
+= p
->vertical_width();
2831 void zero_width_node::vertical_extent(vunits
*min
, vunits
*max
)
2833 node_list_vertical_extent(n
, min
, max
);
2836 overstrike_node::overstrike_node() : list(0), max_width(H0
)
2840 overstrike_node::~overstrike_node()
2842 delete_node_list(list
);
2845 node
*overstrike_node::copy()
2847 overstrike_node
*on
= new overstrike_node
;
2848 for (node
*tem
= list
; tem
; tem
= tem
->next
)
2849 on
->overstrike(tem
->copy());
2853 void overstrike_node::overstrike(node
*n
)
2857 hunits w
= n
->width();
2861 for (p
= &list
; *p
; p
= &(*p
)->next
)
2867 hunits
overstrike_node::width()
2872 bracket_node::bracket_node() : list(0), max_width(H0
)
2876 bracket_node::~bracket_node()
2878 delete_node_list(list
);
2881 node
*bracket_node::copy()
2883 bracket_node
*on
= new bracket_node
;
2888 for (tem
= list
; tem
; tem
= tem
->next
) {
2890 tem
->next
->last
= tem
;
2893 for (tem
= last
; tem
; tem
= tem
->last
)
2894 on
->bracket(tem
->copy());
2898 void bracket_node::bracket(node
*n
)
2902 hunits w
= n
->width();
2909 hunits
bracket_node::width()
2919 int node::merge_space(hunits
, hunits
, hunits
)
2925 space_node
*space_node::free_list
= 0;
2927 void *space_node::operator new(size_t n
)
2929 assert(n
== sizeof(space_node
));
2931 free_list
= (space_node
*)new char[sizeof(space_node
)*BLOCK
];
2932 for (int i
= 0; i
< BLOCK
- 1; i
++)
2933 free_list
[i
].next
= free_list
+ i
+ 1;
2934 free_list
[BLOCK
-1].next
= 0;
2936 space_node
*p
= free_list
;
2937 free_list
= (space_node
*)(free_list
->next
);
2942 inline void space_node::operator delete(void *p
)
2945 ((space_node
*)p
)->next
= free_list
;
2946 free_list
= (space_node
*)p
;
2951 space_node::space_node(hunits nn
, color
*c
, node
*p
)
2952 : node(p
), n(nn
), set(0), was_escape_colon(0), col(c
)
2956 space_node::space_node(hunits nn
, int s
, int flag
, color
*c
, node
*p
)
2957 : node(p
), n(nn
), set(s
), was_escape_colon(flag
), col(c
)
2962 space_node::~space_node()
2967 node
*space_node::copy()
2969 return new space_node(n
, set
, was_escape_colon
, col
);
2972 int space_node::force_tprint()
2977 int space_node::nspaces()
2982 int space_node::merge_space(hunits h
, hunits
, hunits
)
2988 hunits
space_node::width()
2993 void node::spread_space(int*, hunits
*)
2997 void space_node::spread_space(int *nspaces
, hunits
*desired_space
)
3000 assert(*nspaces
> 0);
3001 if (*nspaces
== 1) {
3002 n
+= *desired_space
;
3003 *desired_space
= H0
;
3006 hunits extra
= *desired_space
/ *nspaces
;
3007 *desired_space
-= extra
;
3015 void node::freeze_space()
3019 void space_node::freeze_space()
3024 void node::is_escape_colon()
3028 void space_node::is_escape_colon()
3030 was_escape_colon
= 1;
3033 diverted_space_node::diverted_space_node(vunits d
, node
*p
)
3038 node
*diverted_space_node::copy()
3040 return new diverted_space_node(n
);
3043 diverted_copy_file_node::diverted_copy_file_node(symbol s
, node
*p
)
3044 : node(p
), filename(s
)
3048 node
*diverted_copy_file_node::copy()
3050 return new diverted_copy_file_node(filename
);
3053 int node::ends_sentence()
3058 int kern_pair_node::ends_sentence()
3060 switch (n2
->ends_sentence()) {
3070 return n1
->ends_sentence();
3073 int node_list_ends_sentence(node
*n
)
3075 for (; n
!= 0; n
= n
->next
)
3076 switch (n
->ends_sentence()) {
3089 int dbreak_node::ends_sentence()
3091 return node_list_ends_sentence(none
);
3094 int node::overlaps_horizontally()
3099 int node::overlaps_vertically()
3104 int node::discardable()
3109 int space_node::discardable()
3114 vunits
node::vertical_width()
3119 vunits
vline_node::vertical_width()
3124 vunits
vmotion_node::vertical_width()
3129 int node::set_unformat_flag()
3134 int node::character_type()
3139 hunits
node::subscript_correction()
3144 hunits
node::italic_correction()
3149 hunits
node::left_italic_correction()
3159 /* vertical_extent methods */
3161 void node::vertical_extent(vunits
*min
, vunits
*max
)
3163 vunits v
= vertical_width();
3174 void vline_node::vertical_extent(vunits
*min
, vunits
*max
)
3177 node::vertical_extent(min
, max
);
3180 n
->vertical_extent(&cmin
, &cmax
);
3181 vunits h
= n
->size();
3188 // we print the first character and then move up, so
3190 // we print the last character and then move up h
3203 // we move down by h and then print the first character, so
3213 /* ascii_print methods */
3215 static void ascii_print_reverse_node_list(ascii_output_file
*ascii
, node
*n
)
3219 ascii_print_reverse_node_list(ascii
, n
->next
);
3220 n
->ascii_print(ascii
);
3223 void dbreak_node::ascii_print(ascii_output_file
*ascii
)
3225 ascii_print_reverse_node_list(ascii
, none
);
3228 void kern_pair_node::ascii_print(ascii_output_file
*ascii
)
3230 n1
->ascii_print(ascii
);
3231 n2
->ascii_print(ascii
);
3234 void node::ascii_print(ascii_output_file
*)
3238 void space_node::ascii_print(ascii_output_file
*ascii
)
3244 void hmotion_node::ascii_print(ascii_output_file
*ascii
)
3246 // this is pretty arbitrary
3247 if (n
>= points_to_units(2))
3251 void space_char_hmotion_node::ascii_print(ascii_output_file
*ascii
)
3256 /* asciify methods */
3258 void node::asciify(macro
*m
)
3263 void glyph_node::asciify(macro
*m
)
3265 unsigned char c
= ci
->get_asciify_code();
3267 c
= ci
->get_ascii_code();
3276 void kern_pair_node::asciify(macro
*m
)
3284 static void asciify_reverse_node_list(macro
*m
, node
*n
)
3288 asciify_reverse_node_list(m
, n
->next
);
3292 void dbreak_node::asciify(macro
*m
)
3294 asciify_reverse_node_list(m
, none
);
3299 void ligature_node::asciify(macro
*m
)
3307 void break_char_node::asciify(macro
*m
)
3314 void italic_corrected_node::asciify(macro
*m
)
3321 void left_italic_corrected_node::asciify(macro
*m
)
3330 void hmotion_node::asciify(macro
*m
)
3340 space_char_hmotion_node::space_char_hmotion_node(hunits i
, color
*c
,
3342 : hmotion_node(i
, c
, next
)
3346 void space_char_hmotion_node::asciify(macro
*m
)
3348 m
->append(ESCAPE_SPACE
);
3352 void space_node::asciify(macro
*m
)
3354 if (was_escape_colon
) {
3355 m
->append(ESCAPE_COLON
);
3362 void word_space_node::asciify(macro
*m
)
3364 for (width_list
*w
= orig_width
; w
; w
= w
->next
)
3369 void unbreakable_space_node::asciify(macro
*m
)
3371 m
->append(ESCAPE_TILDE
);
3375 void line_start_node::asciify(macro
*)
3380 void vertical_size_node::asciify(macro
*)
3385 breakpoint
*node::get_breakpoints(hunits
/*width*/, int /*nspaces*/,
3386 breakpoint
*rest
, int /*is_inner*/)
3396 breakpoint
*space_node::get_breakpoints(hunits width
, int ns
,
3397 breakpoint
*rest
, int is_inner
)
3399 if (next
&& next
->discardable())
3401 breakpoint
*bp
= new breakpoint
;
3408 bp
->index
= rest
->index
+ 1;
3418 int space_node::nbreaks()
3420 if (next
&& next
->discardable())
3426 static breakpoint
*node_list_get_breakpoints(node
*p
, hunits
*widthp
,
3427 int ns
, breakpoint
*rest
)
3430 rest
= p
->get_breakpoints(*widthp
,
3432 node_list_get_breakpoints(p
->next
, widthp
, ns
,
3435 *widthp
+= p
->width();
3440 breakpoint
*dbreak_node::get_breakpoints(hunits width
, int ns
,
3441 breakpoint
*rest
, int is_inner
)
3443 breakpoint
*bp
= new breakpoint
;
3446 for (node
*tem
= pre
; tem
!= 0; tem
= tem
->next
)
3447 bp
->width
+= tem
->width();
3452 bp
->index
= rest
->index
+ 1;
3459 return node_list_get_breakpoints(none
, &width
, ns
, bp
);
3462 int dbreak_node::nbreaks()
3465 for (node
*tem
= none
; tem
!= 0; tem
= tem
->next
)
3466 i
+= tem
->nbreaks();
3470 void node::split(int /*where*/, node
** /*prep*/, node
** /*postp*/)
3475 void space_node::split(int where
, node
**pre
, node
**post
)
3483 static void node_list_split(node
*p
, int *wherep
, node
**prep
, node
**postp
)
3487 int nb
= p
->nbreaks();
3488 node_list_split(p
->next
, wherep
, prep
, postp
);
3493 else if (*wherep
< nb
) {
3495 p
->split(*wherep
, prep
, postp
);
3504 void dbreak_node::split(int where
, node
**prep
, node
**postp
)
3514 for (tem
= pre
; tem
->next
!= 0; tem
= tem
->next
)
3525 node_list_split(none
, &where
, prep
, postp
);
3531 hyphenation_type
node::get_hyphenation_type()
3533 return HYPHEN_BOUNDARY
;
3536 hyphenation_type
dbreak_node::get_hyphenation_type()
3538 return HYPHEN_INHIBIT
;
3541 hyphenation_type
kern_pair_node::get_hyphenation_type()
3543 return HYPHEN_MIDDLE
;
3546 hyphenation_type
dummy_node::get_hyphenation_type()
3548 return HYPHEN_MIDDLE
;
3551 hyphenation_type
transparent_dummy_node::get_hyphenation_type()
3553 return HYPHEN_MIDDLE
;
3556 hyphenation_type
hmotion_node::get_hyphenation_type()
3558 return HYPHEN_MIDDLE
;
3561 hyphenation_type
space_char_hmotion_node::get_hyphenation_type()
3563 return HYPHEN_MIDDLE
;
3566 hyphenation_type
overstrike_node::get_hyphenation_type()
3568 return HYPHEN_MIDDLE
;
3571 hyphenation_type
space_node::get_hyphenation_type()
3573 if (was_escape_colon
)
3574 return HYPHEN_MIDDLE
;
3575 return HYPHEN_BOUNDARY
;
3578 hyphenation_type
unbreakable_space_node::get_hyphenation_type()
3580 return HYPHEN_MIDDLE
;
3583 int node::interpret(macro
*)
3588 special_node::special_node(const macro
&m
, int n
)
3589 : mac(m
), no_init_string(n
)
3591 font_size fs
= curenv
->get_font_size();
3592 int char_height
= curenv
->get_char_height();
3593 int char_slant
= curenv
->get_char_slant();
3594 int fontno
= env_definite_font(curenv
);
3595 tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fontno
);
3596 if (curenv
->is_composite())
3597 tf
= tf
->get_plain();
3598 gcol
= curenv
->get_glyph_color();
3599 fcol
= curenv
->get_fill_color();
3602 special_node::special_node(const macro
&m
, tfont
*t
,
3603 color
*gc
, color
*fc
, int n
)
3604 : mac(m
), tf(t
), gcol(gc
), fcol(fc
), no_init_string(n
)
3608 int special_node::same(node
*n
)
3610 return mac
== ((special_node
*)n
)->mac
3611 && tf
== ((special_node
*)n
)->tf
3612 && gcol
== ((special_node
*)n
)->gcol
3613 && fcol
== ((special_node
*)n
)->fcol
3614 && no_init_string
== ((special_node
*)n
)->no_init_string
;
3617 const char *special_node::type()
3619 return "special_node";
3622 int special_node::ends_sentence()
3627 int special_node::force_tprint()
3632 node
*special_node::copy()
3634 return new special_node(mac
, tf
, gcol
, fcol
, no_init_string
);
3637 void special_node::tprint_start(troff_output_file
*out
)
3639 out
->start_special(tf
, gcol
, fcol
, no_init_string
);
3642 void special_node::tprint_char(troff_output_file
*out
, unsigned char c
)
3644 out
->special_char(c
);
3647 void special_node::tprint_end(troff_output_file
*out
)
3652 tfont
*special_node::get_tfont()
3659 suppress_node::suppress_node(int on_or_off
, int issue_limits
)
3660 : is_on(on_or_off
), emit_limits(issue_limits
),
3661 filename(0), position(0), image_id(0)
3665 suppress_node::suppress_node(symbol f
, char p
, int id
)
3666 : is_on(2), emit_limits(0), filename(f
), position(p
), image_id(id
)
3670 suppress_node::suppress_node(int issue_limits
, int on_or_off
,
3671 symbol f
, char p
, int id
)
3672 : is_on(on_or_off
), emit_limits(issue_limits
),
3673 filename(f
), position(p
), image_id(id
)
3677 int suppress_node::same(node
*n
)
3679 return ((is_on
== ((suppress_node
*)n
)->is_on
)
3680 && (emit_limits
== ((suppress_node
*)n
)->emit_limits
)
3681 && (filename
== ((suppress_node
*)n
)->filename
)
3682 && (position
== ((suppress_node
*)n
)->position
)
3683 && (image_id
== ((suppress_node
*)n
)->image_id
));
3686 const char *suppress_node::type()
3688 return "suppress_node";
3691 node
*suppress_node::copy()
3693 return new suppress_node(emit_limits
, is_on
, filename
, position
, image_id
);
3696 int get_reg_int(const char *p
)
3698 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
3700 if (r
&& (r
->get_value(&prev_value
)))
3701 return (int)prev_value
;
3703 warning(WARN_REG
, "number register `%1' not defined", p
);
3707 const char *get_reg_str(const char *p
)
3709 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
3711 return r
->get_string();
3713 warning(WARN_REG
, "register `%1' not defined", p
);
3717 void suppress_node::put(troff_output_file
*out
, const char *s
)
3720 while (s
[i
] != (char)0) {
3721 out
->special_char(s
[i
]);
3727 * We need to remember the start of the image and its name.
3730 static char last_position
= 0;
3731 static const char *last_image_filename
= 0;
3732 static int last_image_id
= 0;
3734 inline int min(int a
, int b
)
3736 return a
< b
? a
: b
;
3740 * tprint - if (is_on == 2)
3741 * remember current position (l, r, c, i) and filename
3747 * emit postscript bounds for image
3749 * if (suppress boolean differs from current state)
3752 * record current page
3753 * set low water mark.
3756 void suppress_node::tprint(troff_output_file
*out
)
3758 int current_page
= topdiv
->get_page_number();
3759 // firstly check to see whether this suppress node contains
3760 // an image filename & position.
3762 // remember position and filename
3763 last_position
= position
;
3764 char *tem
= (char *)last_image_filename
;
3765 last_image_filename
= strsave(filename
.contents());
3768 last_image_id
= image_id
;
3769 // printf("start of image and page = %d\n", current_page);
3772 // now check whether the suppress node requires us to issue limits.
3775 // remember that the filename will contain a %d in which the
3776 // last_image_id is placed
3777 sprintf(name
, last_image_filename
, last_image_id
);
3779 switch (last_position
) {
3781 out
->start_special();
3782 put(out
, "html-tag:.centered-image");
3785 out
->start_special();
3786 put(out
, "html-tag:.right-image");
3789 out
->start_special();
3790 put(out
, "html-tag:.left-image");
3798 out
->start_special();
3799 put(out
, "html-tag:.auto-image ");
3804 // postscript (or other device)
3805 if (suppress_start_page
> 0 && current_page
!= suppress_start_page
)
3806 error("suppression limit registers span more than one page;\n"
3807 "image description %1 will be wrong", image_no
);
3808 // if (topdiv->get_page_number() != suppress_start_page)
3809 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
3810 // topdiv->get_page_number(), suppress_start_page);
3812 // remember that the filename will contain a %d in which the
3813 // image_no is placed
3815 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
3816 topdiv
->get_page_number(),
3817 get_reg_int("opminx"), get_reg_int("opminy"),
3818 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
3819 // page offset + line length
3820 get_reg_int(".o") + get_reg_int(".l"),
3821 name
, hresolution
, vresolution
, get_reg_str(".F"));
3828 // lastly we reset the output registers
3829 reset_output_registers();
3833 suppress_start_page
= current_page
;
3838 int suppress_node::force_tprint()
3843 hunits
suppress_node::width()
3848 /* composite_node */
3850 class composite_node
: public charinfo_node
{
3854 composite_node(node
*, charinfo
*, tfont
*, node
* = 0);
3858 node
*last_char_node();
3860 void tprint(troff_output_file
*);
3861 hyphenation_type
get_hyphenation_type();
3862 void ascii_print(ascii_output_file
*);
3863 void asciify(macro
*);
3864 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
3865 node
*add_self(node
*, hyphen_list
**);
3870 void vertical_extent(vunits
*, vunits
*);
3871 vunits
vertical_width();
3874 composite_node::composite_node(node
*p
, charinfo
*c
, tfont
*t
, node
*x
)
3875 : charinfo_node(c
, x
), n(p
), tf(t
)
3879 composite_node::~composite_node()
3881 delete_node_list(n
);
3884 node
*composite_node::copy()
3886 return new composite_node(copy_node_list(n
), ci
, tf
);
3889 hunits
composite_node::width()
3892 if (tf
->get_constant_space(&x
))
3895 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3898 if (tf
->get_bold(&offset
))
3900 x
+= tf
->get_track_kern();
3904 node
*composite_node::last_char_node()
3909 vunits
composite_node::vertical_width()
3912 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3913 v
+= tem
->vertical_width();
3917 units
composite_node::size()
3919 return tf
->get_size().to_units();
3922 hyphenation_type
composite_node::get_hyphenation_type()
3924 return HYPHEN_MIDDLE
;
3927 void composite_node::asciify(macro
*m
)
3929 unsigned char c
= ci
->get_asciify_code();
3931 c
= ci
->get_ascii_code();
3940 void composite_node::ascii_print(ascii_output_file
*ascii
)
3942 unsigned char c
= ci
->get_ascii_code();
3946 ascii
->outs(ci
->nm
.contents());
3950 hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
3953 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
3956 node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
3958 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
3962 nn
= nn
->add_discretionary_hyphen();
3963 hyphen_list
*pp
= *p
;
3969 tfont
*composite_node::get_tfont()
3974 node
*reverse_node_list(node
*n
)
3986 void composite_node::vertical_extent(vunits
*min
, vunits
*max
)
3988 n
= reverse_node_list(n
);
3989 node_list_vertical_extent(n
, min
, max
);
3990 n
= reverse_node_list(n
);
3993 width_list::width_list(hunits w
, hunits s
)
3994 : width(w
), sentence_width(s
), next(0)
3998 width_list::width_list(width_list
*w
)
3999 : width(w
->width
), sentence_width(w
->sentence_width
), next(0)
4003 word_space_node::word_space_node(hunits d
, color
*c
, width_list
*w
, node
*x
)
4004 : space_node(d
, c
, x
), orig_width(w
), unformat(0)
4008 word_space_node::word_space_node(hunits d
, int s
, color
*c
, width_list
*w
,
4010 : space_node(d
, s
, 0, c
, x
), orig_width(w
), unformat(flag
)
4014 word_space_node::~word_space_node()
4016 width_list
*w
= orig_width
;
4018 width_list
*tmp
= w
;
4024 node
*word_space_node::copy()
4026 assert(orig_width
!= 0);
4027 width_list
*w_old_curr
= orig_width
;
4028 width_list
*w_new_curr
= new width_list(w_old_curr
);
4029 width_list
*w_new
= w_new_curr
;
4030 w_old_curr
= w_old_curr
->next
;
4031 while (w_old_curr
!= 0) {
4032 w_new_curr
->next
= new width_list(w_old_curr
);
4033 w_new_curr
= w_new_curr
->next
;
4034 w_old_curr
= w_old_curr
->next
;
4036 return new word_space_node(n
, set
, col
, w_new
, unformat
);
4039 int word_space_node::set_unformat_flag()
4045 void word_space_node::tprint(troff_output_file
*out
)
4047 out
->fill_color(col
);
4052 int word_space_node::merge_space(hunits h
, hunits sw
, hunits ssw
)
4055 assert(orig_width
!= 0);
4056 width_list
*w
= orig_width
;
4057 for (; w
->next
; w
= w
->next
)
4059 w
->next
= new width_list(sw
, ssw
);
4063 unbreakable_space_node::unbreakable_space_node(hunits d
, color
*c
, node
*x
)
4064 : word_space_node(d
, c
, 0, x
)
4068 unbreakable_space_node::unbreakable_space_node(hunits d
, int s
,
4070 : word_space_node(d
, s
, c
, 0, 0, x
)
4074 node
*unbreakable_space_node::copy()
4076 return new unbreakable_space_node(n
, set
, col
);
4079 int unbreakable_space_node::force_tprint()
4084 breakpoint
*unbreakable_space_node::get_breakpoints(hunits
, int,
4085 breakpoint
*rest
, int)
4090 int unbreakable_space_node::nbreaks()
4095 void unbreakable_space_node::split(int, node
**, node
**)
4100 int unbreakable_space_node::merge_space(hunits
, hunits
, hunits
)
4109 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4110 color
*gc
, color
*fc
)
4111 : npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4113 point
= new hvpair
[npoints
];
4114 for (int i
= 0; i
< npoints
; i
++)
4118 int draw_node::same(node
*n
)
4120 draw_node
*nd
= (draw_node
*)n
;
4121 if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
4122 || gcol
!= nd
->gcol
|| fcol
!= nd
->fcol
)
4124 for (int i
= 0; i
< npoints
; i
++)
4125 if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
4130 const char *draw_node::type()
4135 int draw_node::force_tprint()
4140 draw_node::~draw_node()
4146 hunits
draw_node::width()
4149 for (int i
= 0; i
< npoints
; i
++)
4154 vunits
draw_node::vertical_width()
4159 for (int i
= 0; i
< npoints
; i
++)
4164 node
*draw_node::copy()
4166 return new draw_node(code
, point
, npoints
, sz
, gcol
, fcol
);
4169 void draw_node::tprint(troff_output_file
*out
)
4171 out
->draw(code
, point
, npoints
, sz
, gcol
, fcol
);
4174 /* tprint methods */
4176 void glyph_node::tprint(troff_output_file
*out
)
4178 tfont
*ptf
= tf
->get_plain();
4180 out
->put_char_width(ci
, ptf
, gcol
, fcol
, width(), H0
);
4183 int bold
= tf
->get_bold(&offset
);
4184 hunits w
= ptf
->get_width(ci
);
4187 int cs
= tf
->get_constant_space(&x
);
4197 k
= tf
->get_track_kern();
4199 out
->put_char(ci
, ptf
, gcol
, fcol
);
4202 out
->put_char_width(ci
, ptf
, gcol
, fcol
, w
, k
);
4206 void glyph_node::zero_width_tprint(troff_output_file
*out
)
4208 tfont
*ptf
= tf
->get_plain();
4210 int bold
= tf
->get_bold(&offset
);
4212 int cs
= tf
->get_constant_space(&x
);
4214 x
-= ptf
->get_width(ci
);
4220 out
->put_char(ci
, ptf
, gcol
, fcol
);
4223 out
->put_char(ci
, ptf
, gcol
, fcol
);
4224 out
->right(-offset
);
4230 void break_char_node::tprint(troff_output_file
*t
)
4235 void break_char_node::zero_width_tprint(troff_output_file
*t
)
4237 ch
->zero_width_tprint(t
);
4240 void hline_node::tprint(troff_output_file
*out
)
4250 hunits w
= n
->width();
4252 error("horizontal line drawing character must have positive width");
4263 out
->right(xx
- xx2
);
4266 hunits rem
= x
- w
*i
;
4268 if (n
->overlaps_horizontally()) {
4271 out
->right(rem
- w
);
4281 void vline_node::tprint(troff_output_file
*out
)
4287 vunits h
= n
->size();
4288 int overlaps
= n
->overlaps_vertically();
4293 vunits rem
= y
- i
*h
;
4295 out
->right(n
->width());
4300 n
->zero_width_tprint(out
);
4304 n
->zero_width_tprint(out
);
4313 out
->down(-h
- rem
);
4319 vunits rem
= y
- i
*h
;
4322 out
->right(n
->width());
4327 n
->zero_width_tprint(out
);
4330 n
->zero_width_tprint(out
);
4339 void zero_width_node::tprint(troff_output_file
*out
)
4344 n
->zero_width_tprint(out
);
4347 int hpos
= out
->get_hpos();
4348 int vpos
= out
->get_vpos();
4354 out
->moveto(hpos
, vpos
);
4357 void overstrike_node::tprint(troff_output_file
*out
)
4360 for (node
*tem
= list
; tem
; tem
= tem
->next
) {
4361 hunits x
= (max_width
- tem
->width())/2;
4362 out
->right(x
- pos
);
4364 tem
->zero_width_tprint(out
);
4366 out
->right(max_width
- pos
);
4369 void bracket_node::tprint(troff_output_file
*out
)
4375 for (tem
= list
; tem
; tem
= tem
->next
)
4377 vunits h
= list
->size();
4378 vunits totalh
= h
*npieces
;
4379 vunits y
= (totalh
- h
)/2;
4381 for (tem
= list
; tem
; tem
= tem
->next
) {
4382 tem
->zero_width_tprint(out
);
4385 out
->right(max_width
);
4386 out
->down(totalh
- y
);
4389 void node::tprint(troff_output_file
*)
4393 void node::zero_width_tprint(troff_output_file
*out
)
4395 int hpos
= out
->get_hpos();
4396 int vpos
= out
->get_vpos();
4398 out
->moveto(hpos
, vpos
);
4401 void space_node::tprint(troff_output_file
*out
)
4403 out
->fill_color(col
);
4407 void hmotion_node::tprint(troff_output_file
*out
)
4409 out
->fill_color(col
);
4413 void space_char_hmotion_node::tprint(troff_output_file
*out
)
4415 out
->fill_color(col
);
4417 // we emit the space width as a negative glyph index
4421 out
->put(-n
.to_units());
4427 void vmotion_node::tprint(troff_output_file
*out
)
4429 out
->fill_color(col
);
4433 void kern_pair_node::tprint(troff_output_file
*out
)
4440 static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
4444 tprint_reverse_node_list(out
, n
->next
);
4448 void dbreak_node::tprint(troff_output_file
*out
)
4450 tprint_reverse_node_list(out
, none
);
4453 void composite_node::tprint(troff_output_file
*out
)
4456 int is_bold
= tf
->get_bold(&bold_offset
);
4457 hunits track_kern
= tf
->get_track_kern();
4458 hunits constant_space
;
4459 int is_constant_spaced
= tf
->get_constant_space(&constant_space
);
4461 if (is_constant_spaced
) {
4463 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4472 int hpos
= out
->get_hpos();
4473 int vpos
= out
->get_vpos();
4474 tprint_reverse_node_list(out
, n
);
4475 out
->moveto(hpos
, vpos
);
4476 out
->right(bold_offset
);
4478 tprint_reverse_node_list(out
, n
);
4479 if (is_constant_spaced
)
4482 out
->right(track_kern
);
4485 node
*make_composite_node(charinfo
*s
, environment
*env
)
4487 int fontno
= env_definite_font(env
);
4489 error("no current font");
4492 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4493 node
*n
= charinfo_to_node_list(s
, env
);
4494 font_size fs
= env
->get_font_size();
4495 int char_height
= env
->get_char_height();
4496 int char_slant
= env
->get_char_slant();
4497 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
,
4499 if (env
->is_composite())
4500 tf
= tf
->get_plain();
4501 return new composite_node(n
, s
, tf
);
4504 node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
4506 int fontno
= env_definite_font(env
);
4508 error("no current font");
4511 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4513 int found
= font_table
[fontno
]->contains(s
);
4515 macro
*mac
= s
->get_macro();
4516 if (mac
&& s
->is_fallback())
4517 return make_composite_node(s
, env
);
4518 if (s
->numbered()) {
4519 if (!no_error_message
)
4520 warning(WARN_CHAR
, "can't find numbered character %1",
4524 special_font_list
*sf
= font_table
[fontno
]->sf
;
4525 while (sf
!= 0 && !found
) {
4528 found
= font_table
[fn
]->contains(s
);
4532 symbol f
= font_table
[fontno
]->get_name();
4533 string
gl(f
.contents());
4535 gl
+= s
->nm
.contents();
4537 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
4538 if (ci
&& ci
->get_macro())
4539 return make_composite_node(ci
, env
);
4542 sf
= global_special_fonts
;
4543 while (sf
!= 0 && !found
) {
4546 found
= font_table
[fn
]->contains(s
);
4551 if (mac
&& s
->is_special())
4552 return make_composite_node(s
, env
);
4554 for (fn
= 0; fn
< font_table_size
; fn
++)
4556 && font_table
[fn
]->is_special()
4557 && font_table
[fn
]->contains(s
)) {
4563 if (!no_error_message
&& s
->first_time_not_found()) {
4564 unsigned char input_code
= s
->get_ascii_code();
4565 if (input_code
!= 0) {
4566 if (csgraph(input_code
))
4567 warning(WARN_CHAR
, "can't find character `%1'", input_code
);
4569 warning(WARN_CHAR
, "can't find character with input code %1",
4572 else if (s
->nm
.contents())
4573 warning(WARN_CHAR
, "can't find special character `%1'",
4579 font_size fs
= env
->get_font_size();
4580 int char_height
= env
->get_char_height();
4581 int char_slant
= env
->get_char_slant();
4582 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
4583 if (env
->is_composite())
4584 tf
= tf
->get_plain();
4585 color
*gcol
= env
->get_glyph_color();
4586 color
*fcol
= env
->get_fill_color();
4587 return new glyph_node(s
, tf
, gcol
, fcol
);
4590 node
*make_node(charinfo
*ci
, environment
*env
)
4592 switch (ci
->get_special_translation()) {
4593 case charinfo::TRANSLATE_SPACE
:
4594 return new space_char_hmotion_node(env
->get_space_width(),
4595 env
->get_fill_color());
4596 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4597 return new unbreakable_space_node(env
->get_space_width(),
4598 env
->get_fill_color());
4599 case charinfo::TRANSLATE_DUMMY
:
4600 return new dummy_node
;
4601 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4602 error("translation to \\% ignored in this context");
4605 charinfo
*tem
= ci
->get_translation();
4608 macro
*mac
= ci
->get_macro();
4609 if (mac
&& ci
->is_normal())
4610 return make_composite_node(ci
, env
);
4612 return make_glyph_node(ci
, env
);
4615 int character_exists(charinfo
*ci
, environment
*env
)
4617 if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
4619 charinfo
*tem
= ci
->get_translation();
4622 if (ci
->get_macro())
4624 node
*nd
= make_glyph_node(ci
, env
, 1);
4632 node
*node::add_char(charinfo
*ci
, environment
*env
,
4633 hunits
*widthp
, int *spacep
)
4636 switch (ci
->get_special_translation()) {
4637 case charinfo::TRANSLATE_SPACE
:
4638 res
= new space_char_hmotion_node(env
->get_space_width(),
4639 env
->get_fill_color(), this);
4640 *widthp
+= res
->width();
4642 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4643 res
= new unbreakable_space_node(env
->get_space_width(),
4644 env
->get_fill_color(), this);
4645 res
->freeze_space();
4646 *widthp
+= res
->width();
4647 *spacep
+= res
->nspaces();
4649 case charinfo::TRANSLATE_DUMMY
:
4650 return new dummy_node(this);
4651 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4652 return add_discretionary_hyphen();
4654 charinfo
*tem
= ci
->get_translation();
4657 macro
*mac
= ci
->get_macro();
4658 if (mac
&& ci
->is_normal()) {
4659 res
= make_composite_node(ci
, env
);
4662 *widthp
+= res
->width();
4668 node
*gn
= make_glyph_node(ci
, env
);
4672 hunits old_width
= width();
4673 node
*p
= gn
->merge_self(this);
4675 *widthp
+= gn
->width();
4680 *widthp
+= p
->width() - old_width
;
4686 if (ci
->can_break_before())
4688 if (ci
->can_break_after())
4691 node
*next1
= res
->next
;
4693 res
= new break_char_node(res
, break_code
, env
->get_fill_color(), next1
);
4701 int same_node(node
*n1
, node
*n2
)
4705 return n1
->type() == n2
->type() && n1
->same(n2
);
4713 int same_node_list(node
*n1
, node
*n2
)
4716 if (n1
->type() != n2
->type() || !n1
->same(n2
))
4724 int extra_size_node::same(node
*nd
)
4726 return n
== ((extra_size_node
*)nd
)->n
;
4729 const char *extra_size_node::type()
4731 return "extra_size_node";
4734 int extra_size_node::force_tprint()
4739 int vertical_size_node::same(node
*nd
)
4741 return n
== ((vertical_size_node
*)nd
)->n
;
4744 const char *vertical_size_node::type()
4746 return "vertical_size_node";
4749 int vertical_size_node::set_unformat_flag()
4754 int vertical_size_node::force_tprint()
4759 int hmotion_node::same(node
*nd
)
4761 return n
== ((hmotion_node
*)nd
)->n
4762 && col
== ((hmotion_node
*)nd
)->col
;
4765 const char *hmotion_node::type()
4767 return "hmotion_node";
4770 int hmotion_node::set_unformat_flag()
4776 int hmotion_node::force_tprint()
4781 node
*hmotion_node::add_self(node
*n
, hyphen_list
**p
)
4784 hyphen_list
*pp
= *p
;
4790 hyphen_list
*hmotion_node::get_hyphen_list(hyphen_list
*tail
, int *)
4792 return new hyphen_list(0, tail
);
4795 int space_char_hmotion_node::same(node
*nd
)
4797 return n
== ((space_char_hmotion_node
*)nd
)->n
4798 && col
== ((space_char_hmotion_node
*)nd
)->col
;
4801 const char *space_char_hmotion_node::type()
4803 return "space_char_hmotion_node";
4806 int space_char_hmotion_node::force_tprint()
4811 node
*space_char_hmotion_node::add_self(node
*n
, hyphen_list
**p
)
4814 hyphen_list
*pp
= *p
;
4820 hyphen_list
*space_char_hmotion_node::get_hyphen_list(hyphen_list
*tail
,
4823 return new hyphen_list(0, tail
);
4826 int vmotion_node::same(node
*nd
)
4828 return n
== ((vmotion_node
*)nd
)->n
4829 && col
== ((vmotion_node
*)nd
)->col
;
4832 const char *vmotion_node::type()
4834 return "vmotion_node";
4837 int vmotion_node::force_tprint()
4842 int hline_node::same(node
*nd
)
4844 return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
4847 const char *hline_node::type()
4849 return "hline_node";
4852 int hline_node::force_tprint()
4857 int vline_node::same(node
*nd
)
4859 return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
4862 const char *vline_node::type()
4864 return "vline_node";
4867 int vline_node::force_tprint()
4872 int dummy_node::same(node
* /*nd*/)
4877 const char *dummy_node::type()
4879 return "dummy_node";
4882 int dummy_node::force_tprint()
4887 int transparent_dummy_node::same(node
* /*nd*/)
4892 const char *transparent_dummy_node::type()
4894 return "transparent_dummy_node";
4897 int transparent_dummy_node::force_tprint()
4902 int transparent_dummy_node::ends_sentence()
4907 int zero_width_node::same(node
*nd
)
4909 return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
4912 const char *zero_width_node::type()
4914 return "zero_width_node";
4917 int zero_width_node::force_tprint()
4922 int italic_corrected_node::same(node
*nd
)
4924 return (x
== ((italic_corrected_node
*)nd
)->x
4925 && same_node(n
, ((italic_corrected_node
*)nd
)->n
));
4928 const char *italic_corrected_node::type()
4930 return "italic_corrected_node";
4933 int italic_corrected_node::force_tprint()
4938 left_italic_corrected_node::left_italic_corrected_node(node
*x
)
4943 left_italic_corrected_node::~left_italic_corrected_node()
4948 node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
4951 hunits lic
= gn
->left_italic_correction();
4952 if (!lic
.is_zero()) {
4959 node
*nd
= n
->merge_glyph_node(gn
);
4962 x
= n
->left_italic_correction();
4969 node
*left_italic_corrected_node::copy()
4971 left_italic_corrected_node
*nd
= new left_italic_corrected_node
;
4979 void left_italic_corrected_node::tprint(troff_output_file
*out
)
4987 const char *left_italic_corrected_node::type()
4989 return "left_italic_corrected_node";
4992 int left_italic_corrected_node::force_tprint()
4997 int left_italic_corrected_node::same(node
*nd
)
4999 return (x
== ((left_italic_corrected_node
*)nd
)->x
5000 && same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
5003 void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
5006 n
->ascii_print(out
);
5009 hunits
left_italic_corrected_node::width()
5011 return n
? n
->width() + x
: H0
;
5014 void left_italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
5017 n
->vertical_extent(min
, max
);
5019 node::vertical_extent(min
, max
);
5022 hunits
left_italic_corrected_node::skew()
5024 return n
? n
->skew() + x
/2 : H0
;
5027 hunits
left_italic_corrected_node::subscript_correction()
5029 return n
? n
->subscript_correction() : H0
;
5032 hunits
left_italic_corrected_node::italic_correction()
5034 return n
? n
->italic_correction() : H0
;
5037 int left_italic_corrected_node::ends_sentence()
5039 return n
? n
->ends_sentence() : 0;
5042 int left_italic_corrected_node::overlaps_horizontally()
5044 return n
? n
->overlaps_horizontally() : 0;
5047 int left_italic_corrected_node::overlaps_vertically()
5049 return n
? n
->overlaps_vertically() : 0;
5052 node
*left_italic_corrected_node::last_char_node()
5054 return n
? n
->last_char_node() : 0;
5057 tfont
*left_italic_corrected_node::get_tfont()
5059 return n
? n
->get_tfont() : 0;
5062 hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
5065 return n
->get_hyphenation_type();
5067 return HYPHEN_MIDDLE
;
5070 hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
5073 return n
? n
->get_hyphen_list(tail
, count
) : tail
;
5076 node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
5079 nd
= new left_italic_corrected_node(nd
);
5080 nd
= n
->add_self(nd
, p
);
5087 int left_italic_corrected_node::character_type()
5089 return n
? n
->character_type() : 0;
5092 int overstrike_node::same(node
*nd
)
5094 return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
5097 const char *overstrike_node::type()
5099 return "overstrike_node";
5102 int overstrike_node::force_tprint()
5107 node
*overstrike_node::add_self(node
*n
, hyphen_list
**p
)
5110 hyphen_list
*pp
= *p
;
5116 hyphen_list
*overstrike_node::get_hyphen_list(hyphen_list
*tail
, int *)
5118 return new hyphen_list(0, tail
);
5121 int bracket_node::same(node
*nd
)
5123 return same_node_list(list
, ((bracket_node
*)nd
)->list
);
5126 const char *bracket_node::type()
5128 return "bracket_node";
5131 int bracket_node::force_tprint()
5136 int composite_node::same(node
*nd
)
5138 return ci
== ((composite_node
*)nd
)->ci
5139 && same_node_list(n
, ((composite_node
*)nd
)->n
);
5142 const char *composite_node::type()
5144 return "composite_node";
5147 int composite_node::force_tprint()
5152 int glyph_node::same(node
*nd
)
5154 return ci
== ((glyph_node
*)nd
)->ci
5155 && tf
== ((glyph_node
*)nd
)->tf
5156 && gcol
== ((glyph_node
*)nd
)->gcol
5157 && fcol
== ((glyph_node
*)nd
)->fcol
;
5160 const char *glyph_node::type()
5162 return "glyph_node";
5165 int glyph_node::force_tprint()
5170 int ligature_node::same(node
*nd
)
5172 return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
5173 && same_node(n2
, ((ligature_node
*)nd
)->n2
)
5174 && glyph_node::same(nd
));
5177 const char *ligature_node::type()
5179 return "ligature_node";
5182 int ligature_node::force_tprint()
5187 int kern_pair_node::same(node
*nd
)
5189 return (amount
== ((kern_pair_node
*)nd
)->amount
5190 && same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
5191 && same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
5194 const char *kern_pair_node::type()
5196 return "kern_pair_node";
5199 int kern_pair_node::force_tprint()
5204 int dbreak_node::same(node
*nd
)
5206 return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
5207 && same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
5208 && same_node_list(post
, ((dbreak_node
*)nd
)->post
));
5211 const char *dbreak_node::type()
5213 return "dbreak_node";
5216 int dbreak_node::force_tprint()
5221 int break_char_node::same(node
*nd
)
5223 return break_code
== ((break_char_node
*)nd
)->break_code
5224 && col
== ((break_char_node
*)nd
)->col
5225 && same_node(ch
, ((break_char_node
*)nd
)->ch
);
5228 const char *break_char_node::type()
5230 return "break_char_node";
5233 int break_char_node::force_tprint()
5238 int line_start_node::same(node
* /*nd*/)
5243 const char *line_start_node::type()
5245 return "line_start_node";
5248 int line_start_node::force_tprint()
5253 int space_node::same(node
*nd
)
5255 return n
== ((space_node
*)nd
)->n
5256 && set
== ((space_node
*)nd
)->set
5257 && col
== ((space_node
*)nd
)->col
;
5260 const char *space_node::type()
5262 return "space_node";
5265 int word_space_node::same(node
*nd
)
5267 return n
== ((word_space_node
*)nd
)->n
5268 && set
== ((word_space_node
*)nd
)->set
5269 && col
== ((word_space_node
*)nd
)->col
;
5272 const char *word_space_node::type()
5274 return "word_space_node";
5277 int word_space_node::force_tprint()
5282 void unbreakable_space_node::tprint(troff_output_file
*out
)
5284 out
->fill_color(col
);
5286 // we emit the space width as a negative glyph index
5290 out
->put(-n
.to_units());
5296 int unbreakable_space_node::same(node
*nd
)
5298 return n
== ((unbreakable_space_node
*)nd
)->n
5299 && set
== ((unbreakable_space_node
*)nd
)->set
5300 && col
== ((unbreakable_space_node
*)nd
)->col
;
5303 const char *unbreakable_space_node::type()
5305 return "unbreakable_space_node";
5308 node
*unbreakable_space_node::add_self(node
*n
, hyphen_list
**p
)
5311 hyphen_list
*pp
= *p
;
5317 hyphen_list
*unbreakable_space_node::get_hyphen_list(hyphen_list
*tail
, int *)
5319 return new hyphen_list(0, tail
);
5322 int diverted_space_node::same(node
*nd
)
5324 return n
== ((diverted_space_node
*)nd
)->n
;
5327 const char *diverted_space_node::type()
5329 return "diverted_space_node";
5332 int diverted_space_node::force_tprint()
5337 int diverted_copy_file_node::same(node
*nd
)
5339 return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
5342 const char *diverted_copy_file_node::type()
5344 return "diverted_copy_file_node";
5347 int diverted_copy_file_node::force_tprint()
5352 // Grow the font_table so that its size is > n.
5354 static void grow_font_table(int n
)
5356 assert(n
>= font_table_size
);
5357 font_info
**old_font_table
= font_table
;
5358 int old_font_table_size
= font_table_size
;
5359 font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
5360 if (font_table_size
<= n
)
5361 font_table_size
= n
+ 10;
5362 font_table
= new font_info
*[font_table_size
];
5363 if (old_font_table_size
)
5364 memcpy(font_table
, old_font_table
,
5365 old_font_table_size
*sizeof(font_info
*));
5366 a_delete old_font_table
;
5367 for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
5371 dictionary
font_translation_dictionary(17);
5373 static symbol
get_font_translation(symbol nm
)
5375 void *p
= font_translation_dictionary
.lookup(nm
);
5376 return p
? symbol((char *)p
) : nm
;
5379 dictionary
font_dictionary(50);
5381 static int mount_font_no_translate(int n
, symbol name
, symbol external_name
)
5384 // We store the address of this char in font_dictionary to indicate
5385 // that we've previously tried to mount the font and failed.
5388 void *p
= font_dictionary
.lookup(external_name
);
5391 fm
= font::load_font(external_name
.contents(), ¬_found
);
5394 warning(WARN_FONT
, "can't find font `%1'", external_name
.contents());
5395 (void)font_dictionary
.lookup(external_name
, &a_char
);
5398 (void)font_dictionary
.lookup(name
, fm
);
5400 else if (p
== &a_char
) {
5402 error("invalid font `%1'", external_name
.contents());
5408 if (n
>= font_table_size
) {
5409 if (n
- font_table_size
> 1000) {
5410 error("font position too much larger than first unused position");
5415 else if (font_table
[n
] != 0)
5416 delete font_table
[n
];
5417 font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
5418 font_family::invalidate_fontno(n
);
5422 int mount_font(int n
, symbol name
, symbol external_name
)
5425 name
= get_font_translation(name
);
5426 if (external_name
.is_null())
5427 external_name
= name
;
5429 external_name
= get_font_translation(external_name
);
5430 return mount_font_no_translate(n
, name
, external_name
);
5433 void mount_style(int n
, symbol name
)
5436 if (n
>= font_table_size
) {
5437 if (n
- font_table_size
> 1000) {
5438 error("font position too much larger than first unused position");
5443 else if (font_table
[n
] != 0)
5444 delete font_table
[n
];
5445 font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
5446 font_family::invalidate_fontno(n
);
5449 /* global functions */
5451 void font_translate()
5453 symbol from
= get_name(1);
5454 if (!from
.is_null()) {
5455 symbol to
= get_name();
5456 if (to
.is_null() || from
== to
)
5457 font_translation_dictionary
.remove(from
);
5459 (void)font_translation_dictionary
.lookup(from
, (void *)to
.contents());
5464 void font_position()
5467 if (get_integer(&n
)) {
5469 error("negative font position");
5471 symbol internal_name
= get_name(1);
5472 if (!internal_name
.is_null()) {
5473 symbol external_name
= get_long_name();
5474 mount_font(n
, internal_name
, external_name
); // ignore error
5481 font_family::font_family(symbol s
)
5482 : map_size(10), nm(s
)
5484 map
= new int[map_size
];
5485 for (int i
= 0; i
< map_size
; i
++)
5489 font_family::~font_family()
5494 int font_family::make_definite(int i
)
5497 if (i
< map_size
&& map
[i
] >= 0)
5500 if (i
< font_table_size
&& font_table
[i
] != 0) {
5501 if (i
>= map_size
) {
5502 int old_map_size
= map_size
;
5508 map
= new int[map_size
];
5509 memcpy(map
, old_map
, old_map_size
*sizeof(int));
5511 for (int j
= old_map_size
; j
< map_size
; j
++)
5514 if (font_table
[i
]->is_style()) {
5515 symbol sty
= font_table
[i
]->get_name();
5516 symbol f
= concat(nm
, sty
);
5518 // don't use symbol_fontno, because that might return a style
5519 // and because we don't want to translate the name
5520 for (n
= 0; n
< font_table_size
; n
++)
5521 if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
5522 && !font_table
[n
]->is_style())
5524 if (n
>= font_table_size
) {
5525 n
= next_available_font_position();
5526 if (!mount_font_no_translate(n
, f
, f
))
5542 dictionary
family_dictionary(5);
5544 font_family
*lookup_family(symbol nm
)
5546 font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
5548 f
= new font_family(nm
);
5549 (void)family_dictionary
.lookup(nm
, f
);
5554 void font_family::invalidate_fontno(int n
)
5556 assert(n
>= 0 && n
< font_table_size
);
5557 dictionary_iterator
iter(family_dictionary
);
5560 while (iter
.get(&nm
, (void **)&fam
)) {
5561 int map_size
= fam
->map_size
;
5564 for (int i
= 0; i
< map_size
; i
++)
5565 if (fam
->map
[i
] == n
)
5573 if (get_integer(&n
)) {
5575 error("negative font position");
5577 symbol internal_name
= get_name(1);
5578 if (!internal_name
.is_null())
5579 mount_style(n
, internal_name
);
5585 static int get_fontno()
5589 if (tok
.delimiter()) {
5590 symbol s
= get_name(1);
5592 n
= symbol_fontno(s
);
5594 n
= next_available_font_position();
5595 if (!mount_font(n
, s
))
5598 return curenv
->get_family()->make_definite(n
);
5601 else if (get_integer(&n
)) {
5602 if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
5603 error("bad font number");
5605 return curenv
->get_family()->make_definite(n
);
5610 static int underline_fontno
= 2;
5612 void underline_font()
5614 int n
= get_fontno();
5616 underline_fontno
= n
;
5620 int get_underline_fontno()
5622 return underline_fontno
;
5625 void define_font_special_character()
5627 int n
= get_fontno();
5632 symbol f
= font_table
[n
]->get_name();
5633 do_define_character(CHAR_FONT_SPECIAL
, f
.contents());
5636 void remove_font_special_character()
5638 int n
= get_fontno();
5643 symbol f
= font_table
[n
]->get_name();
5644 while (!tok
.newline() && !tok
.eof()) {
5645 if (!tok
.space() && !tok
.tab()) {
5646 charinfo
*s
= tok
.get_char(1);
5647 string
gl(f
.contents());
5649 gl
+= s
->nm
.contents();
5651 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
5654 macro
*m
= ci
->set_macro(0);
5663 static void read_special_fonts(special_font_list
**sp
)
5665 special_font_list
*s
= *sp
;
5668 special_font_list
*tem
= s
;
5672 special_font_list
**p
= sp
;
5674 int i
= get_fontno();
5676 special_font_list
*tem
= new special_font_list
;
5685 void font_special_request()
5687 int n
= get_fontno();
5689 read_special_fonts(&font_table
[n
]->sf
);
5693 void special_request()
5695 read_special_fonts(&global_special_fonts
);
5699 int next_available_font_position()
5702 for (i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
5707 int symbol_fontno(symbol s
)
5709 s
= get_font_translation(s
);
5710 for (int i
= 0; i
< font_table_size
; i
++)
5711 if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
5716 int is_good_fontno(int n
)
5718 return n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0;
5721 int get_bold_fontno(int n
)
5723 if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
5725 if (font_table
[n
]->get_bold(&offset
))
5726 return offset
.to_units() + 1;
5734 hunits
env_digit_width(environment
*env
)
5736 node
*n
= make_glyph_node(charset_table
['0'], env
);
5738 hunits x
= n
->width();
5746 hunits
env_space_width(environment
*env
)
5748 int fn
= env_definite_font(env
);
5749 font_size fs
= env
->get_font_size();
5750 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5751 return scale(fs
.to_units()/3, env
->get_space_size(), 12);
5753 return font_table
[fn
]->get_space_width(fs
, env
->get_space_size());
5756 hunits
env_sentence_space_width(environment
*env
)
5758 int fn
= env_definite_font(env
);
5759 font_size fs
= env
->get_font_size();
5760 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5761 return scale(fs
.to_units()/3, env
->get_sentence_space_size(), 12);
5763 return font_table
[fn
]->get_space_width(fs
, env
->get_sentence_space_size());
5766 hunits
env_half_narrow_space_width(environment
*env
)
5768 int fn
= env_definite_font(env
);
5769 font_size fs
= env
->get_font_size();
5770 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5773 return font_table
[fn
]->get_half_narrow_space_width(fs
);
5776 hunits
env_narrow_space_width(environment
*env
)
5778 int fn
= env_definite_font(env
);
5779 font_size fs
= env
->get_font_size();
5780 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5783 return font_table
[fn
]->get_narrow_space_width(fs
);
5788 int n
= get_fontno();
5791 if (tok
.delimiter()) {
5792 int f
= get_fontno();
5795 if (has_arg() && get_number(&offset
, 'u') && offset
>= 1)
5796 font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
5798 font_table
[f
]->conditional_unbold(n
);
5803 if (get_number(&offset
, 'u') && offset
>= 1)
5804 font_table
[n
]->set_bold(hunits(offset
- 1));
5806 font_table
[n
]->unbold();
5810 font_table
[n
]->unbold();
5815 track_kerning_function::track_kerning_function() : non_zero(0)
5819 track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
5820 int max_s
, hunits max_a
)
5821 : non_zero(1), min_size(min_s
), min_amount(min_a
), max_size(max_s
),
5826 int track_kerning_function::operator==(const track_kerning_function
&tk
)
5830 && min_size
== tk
.min_size
5831 && min_amount
== tk
.min_amount
5832 && max_size
== tk
.max_size
5833 && max_amount
== tk
.max_amount
);
5835 return !tk
.non_zero
;
5838 int track_kerning_function::operator!=(const track_kerning_function
&tk
)
5841 return (!tk
.non_zero
5842 || min_size
!= tk
.min_size
5843 || min_amount
!= tk
.min_amount
5844 || max_size
!= tk
.max_size
5845 || max_amount
!= tk
.max_amount
);
5850 hunits
track_kerning_function::compute(int size
)
5853 if (max_size
<= min_size
)
5855 else if (size
<= min_size
)
5857 else if (size
>= max_size
)
5860 return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
5861 + scale(min_amount
, max_size
- size
, max_size
- min_size
));
5869 int n
= get_fontno();
5872 hunits min_a
, max_a
;
5874 && get_number(&min_s
, 'z')
5875 && get_hunits(&min_a
, 'p')
5876 && get_number(&max_s
, 'z')
5877 && get_hunits(&max_a
, 'p')) {
5878 track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
5879 font_table
[n
]->set_track_kern(tk
);
5882 track_kerning_function tk
;
5883 font_table
[n
]->set_track_kern(tk
);
5889 void constant_space()
5891 int n
= get_fontno();
5894 if (!has_arg() || !get_integer(&x
))
5895 font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
5897 if (!has_arg() || !get_number(&y
, 'z'))
5898 font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
5900 font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
5912 if (has_arg() && get_integer(&lig
) && lig
>= 0 && lig
<= 2)
5913 global_ligature_mode
= lig
;
5915 global_ligature_mode
= 1;
5922 if (has_arg() && get_integer(&k
))
5923 global_kern_mode
= k
!= 0;
5925 global_kern_mode
= 1;
5929 void set_soft_hyphen_char()
5931 soft_hyphen_char
= get_optional_char();
5932 if (!soft_hyphen_char
)
5933 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);
5939 if (suppress_output_flag
)
5940 the_output
= new suppress_output_file
;
5941 else if (ascii_output_flag
)
5942 the_output
= new ascii_output_file
;
5944 the_output
= new troff_output_file
;
5947 class next_available_font_position_reg
: public reg
{
5949 const char *get_string();
5952 const char *next_available_font_position_reg::get_string()
5954 return i_to_a(next_available_font_position());
5957 class printing_reg
: public reg
{
5959 const char *get_string();
5962 const char *printing_reg::get_string()
5965 return the_output
->is_printing() ? "1" : "0";
5970 void init_node_requests()
5972 init_request("bd", bold_font
);
5973 init_request("cs", constant_space
);
5974 init_request("fp", font_position
);
5975 init_request("fschar", define_font_special_character
);
5976 init_request("fspecial", font_special_request
);
5977 init_request("ftr", font_translate
);
5978 init_request("kern", kern_request
);
5979 init_request("lg", ligature
);
5980 init_request("rfschar", remove_font_special_character
);
5981 init_request("shc", set_soft_hyphen_char
);
5982 init_request("special", special_request
);
5983 init_request("sty", style
);
5984 init_request("tkf", track_kern
);
5985 init_request("uf", underline_font
);
5986 number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
5987 number_reg_dictionary
.define(".kern",
5988 new constant_int_reg(&global_kern_mode
));
5989 number_reg_dictionary
.define(".lg",
5990 new constant_int_reg(&global_ligature_mode
));
5991 number_reg_dictionary
.define(".P", new printing_reg
);
5992 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);