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_sz
)
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_node
= 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
*wd
)
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
;
2884 node
*last_node
= 0;
2888 for (tem
= list
; tem
; tem
= tem
->next
) {
2890 tem
->next
->last
= tem
;
2893 for (tem
= last_node
; 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 *n_spaces
, hunits
*desired_space
)
3000 assert(*n_spaces
> 0);
3001 if (*n_spaces
== 1) {
3002 n
+= *desired_space
;
3003 *desired_space
= H0
;
3006 hunits extra
= *desired_space
/ *n_spaces
;
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
, nxt
)
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 wd
, 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 wd
, 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
, &wd
, 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 if (last_image_filename
== (char *) 0)
3780 sprintf(name
, last_image_filename
, last_image_id
);
3782 switch (last_position
) {
3784 out
->start_special();
3785 put(out
, "html-tag:.centered-image");
3788 out
->start_special();
3789 put(out
, "html-tag:.right-image");
3792 out
->start_special();
3793 put(out
, "html-tag:.left-image");
3801 out
->start_special();
3802 put(out
, "html-tag:.auto-image ");
3807 // postscript (or other device)
3808 if (suppress_start_page
> 0 && current_page
!= suppress_start_page
)
3809 error("suppression limit registers span more than one page;\n"
3810 "image description %1 will be wrong", image_no
);
3811 // if (topdiv->get_page_number() != suppress_start_page)
3812 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
3813 // topdiv->get_page_number(), suppress_start_page);
3815 // remember that the filename will contain a %d in which the
3816 // image_no is placed
3818 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
3819 topdiv
->get_page_number(),
3820 get_reg_int("opminx"), get_reg_int("opminy"),
3821 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
3822 // page offset + line length
3823 get_reg_int(".o") + get_reg_int(".l"),
3824 name
, hresolution
, vresolution
, get_reg_str(".F"));
3831 // lastly we reset the output registers
3832 reset_output_registers();
3836 suppress_start_page
= current_page
;
3841 int suppress_node::force_tprint()
3846 hunits
suppress_node::width()
3851 /* composite_node */
3853 class composite_node
: public charinfo_node
{
3857 composite_node(node
*, charinfo
*, tfont
*, node
* = 0);
3861 node
*last_char_node();
3863 void tprint(troff_output_file
*);
3864 hyphenation_type
get_hyphenation_type();
3865 void ascii_print(ascii_output_file
*);
3866 void asciify(macro
*);
3867 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
3868 node
*add_self(node
*, hyphen_list
**);
3873 void vertical_extent(vunits
*, vunits
*);
3874 vunits
vertical_width();
3877 composite_node::composite_node(node
*p
, charinfo
*c
, tfont
*t
, node
*x
)
3878 : charinfo_node(c
, x
), n(p
), tf(t
)
3882 composite_node::~composite_node()
3884 delete_node_list(n
);
3887 node
*composite_node::copy()
3889 return new composite_node(copy_node_list(n
), ci
, tf
);
3892 hunits
composite_node::width()
3895 if (tf
->get_constant_space(&x
))
3898 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3901 if (tf
->get_bold(&offset
))
3903 x
+= tf
->get_track_kern();
3907 node
*composite_node::last_char_node()
3912 vunits
composite_node::vertical_width()
3915 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3916 v
+= tem
->vertical_width();
3920 units
composite_node::size()
3922 return tf
->get_size().to_units();
3925 hyphenation_type
composite_node::get_hyphenation_type()
3927 return HYPHEN_MIDDLE
;
3930 void composite_node::asciify(macro
*m
)
3932 unsigned char c
= ci
->get_asciify_code();
3934 c
= ci
->get_ascii_code();
3943 void composite_node::ascii_print(ascii_output_file
*ascii
)
3945 unsigned char c
= ci
->get_ascii_code();
3949 ascii
->outs(ci
->nm
.contents());
3953 hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
3956 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
3959 node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
3961 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
3965 nn
= nn
->add_discretionary_hyphen();
3966 hyphen_list
*pp
= *p
;
3972 tfont
*composite_node::get_tfont()
3977 node
*reverse_node_list(node
*n
)
3989 void composite_node::vertical_extent(vunits
*minimum
, vunits
*maximum
)
3991 n
= reverse_node_list(n
);
3992 node_list_vertical_extent(n
, minimum
, maximum
);
3993 n
= reverse_node_list(n
);
3996 width_list::width_list(hunits w
, hunits s
)
3997 : width(w
), sentence_width(s
), next(0)
4001 width_list::width_list(width_list
*w
)
4002 : width(w
->width
), sentence_width(w
->sentence_width
), next(0)
4006 word_space_node::word_space_node(hunits d
, color
*c
, width_list
*w
, node
*x
)
4007 : space_node(d
, c
, x
), orig_width(w
), unformat(0)
4011 word_space_node::word_space_node(hunits d
, int s
, color
*c
, width_list
*w
,
4013 : space_node(d
, s
, 0, c
, x
), orig_width(w
), unformat(flag
)
4017 word_space_node::~word_space_node()
4019 width_list
*w
= orig_width
;
4021 width_list
*tmp
= w
;
4027 node
*word_space_node::copy()
4029 assert(orig_width
!= 0);
4030 width_list
*w_old_curr
= orig_width
;
4031 width_list
*w_new_curr
= new width_list(w_old_curr
);
4032 width_list
*w_new
= w_new_curr
;
4033 w_old_curr
= w_old_curr
->next
;
4034 while (w_old_curr
!= 0) {
4035 w_new_curr
->next
= new width_list(w_old_curr
);
4036 w_new_curr
= w_new_curr
->next
;
4037 w_old_curr
= w_old_curr
->next
;
4039 return new word_space_node(n
, set
, col
, w_new
, unformat
);
4042 int word_space_node::set_unformat_flag()
4048 void word_space_node::tprint(troff_output_file
*out
)
4050 out
->fill_color(col
);
4055 int word_space_node::merge_space(hunits h
, hunits sw
, hunits ssw
)
4058 assert(orig_width
!= 0);
4059 width_list
*w
= orig_width
;
4060 for (; w
->next
; w
= w
->next
)
4062 w
->next
= new width_list(sw
, ssw
);
4066 unbreakable_space_node::unbreakable_space_node(hunits d
, color
*c
, node
*x
)
4067 : word_space_node(d
, c
, 0, x
)
4071 unbreakable_space_node::unbreakable_space_node(hunits d
, int s
,
4073 : word_space_node(d
, s
, c
, 0, 0, x
)
4077 node
*unbreakable_space_node::copy()
4079 return new unbreakable_space_node(n
, set
, col
);
4082 int unbreakable_space_node::force_tprint()
4087 breakpoint
*unbreakable_space_node::get_breakpoints(hunits
, int,
4088 breakpoint
*rest
, int)
4093 int unbreakable_space_node::nbreaks()
4098 void unbreakable_space_node::split(int, node
**, node
**)
4103 int unbreakable_space_node::merge_space(hunits
, hunits
, hunits
)
4112 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4113 color
*gc
, color
*fc
)
4114 : npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4116 point
= new hvpair
[npoints
];
4117 for (int i
= 0; i
< npoints
; i
++)
4121 int draw_node::same(node
*n
)
4123 draw_node
*nd
= (draw_node
*)n
;
4124 if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
4125 || gcol
!= nd
->gcol
|| fcol
!= nd
->fcol
)
4127 for (int i
= 0; i
< npoints
; i
++)
4128 if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
4133 const char *draw_node::type()
4138 int draw_node::force_tprint()
4143 draw_node::~draw_node()
4149 hunits
draw_node::width()
4152 for (int i
= 0; i
< npoints
; i
++)
4157 vunits
draw_node::vertical_width()
4162 for (int i
= 0; i
< npoints
; i
++)
4167 node
*draw_node::copy()
4169 return new draw_node(code
, point
, npoints
, sz
, gcol
, fcol
);
4172 void draw_node::tprint(troff_output_file
*out
)
4174 out
->draw(code
, point
, npoints
, sz
, gcol
, fcol
);
4177 /* tprint methods */
4179 void glyph_node::tprint(troff_output_file
*out
)
4181 tfont
*ptf
= tf
->get_plain();
4183 out
->put_char_width(ci
, ptf
, gcol
, fcol
, width(), H0
);
4186 int bold
= tf
->get_bold(&offset
);
4187 hunits w
= ptf
->get_width(ci
);
4190 int cs
= tf
->get_constant_space(&x
);
4200 k
= tf
->get_track_kern();
4202 out
->put_char(ci
, ptf
, gcol
, fcol
);
4205 out
->put_char_width(ci
, ptf
, gcol
, fcol
, w
, k
);
4209 void glyph_node::zero_width_tprint(troff_output_file
*out
)
4211 tfont
*ptf
= tf
->get_plain();
4213 int bold
= tf
->get_bold(&offset
);
4215 int cs
= tf
->get_constant_space(&x
);
4217 x
-= ptf
->get_width(ci
);
4223 out
->put_char(ci
, ptf
, gcol
, fcol
);
4226 out
->put_char(ci
, ptf
, gcol
, fcol
);
4227 out
->right(-offset
);
4233 void break_char_node::tprint(troff_output_file
*t
)
4238 void break_char_node::zero_width_tprint(troff_output_file
*t
)
4240 ch
->zero_width_tprint(t
);
4243 void hline_node::tprint(troff_output_file
*out
)
4253 hunits w
= n
->width();
4255 error("horizontal line drawing character must have positive width");
4266 out
->right(xx
- xx2
);
4269 hunits rem
= x
- w
*i
;
4271 if (n
->overlaps_horizontally()) {
4274 out
->right(rem
- w
);
4284 void vline_node::tprint(troff_output_file
*out
)
4290 vunits h
= n
->size();
4291 int overlaps
= n
->overlaps_vertically();
4296 vunits rem
= y
- i
*h
;
4298 out
->right(n
->width());
4303 n
->zero_width_tprint(out
);
4307 n
->zero_width_tprint(out
);
4316 out
->down(-h
- rem
);
4322 vunits rem
= y
- i
*h
;
4325 out
->right(n
->width());
4330 n
->zero_width_tprint(out
);
4333 n
->zero_width_tprint(out
);
4342 void zero_width_node::tprint(troff_output_file
*out
)
4347 n
->zero_width_tprint(out
);
4350 int hpos
= out
->get_hpos();
4351 int vpos
= out
->get_vpos();
4357 out
->moveto(hpos
, vpos
);
4360 void overstrike_node::tprint(troff_output_file
*out
)
4363 for (node
*tem
= list
; tem
; tem
= tem
->next
) {
4364 hunits x
= (max_width
- tem
->width())/2;
4365 out
->right(x
- pos
);
4367 tem
->zero_width_tprint(out
);
4369 out
->right(max_width
- pos
);
4372 void bracket_node::tprint(troff_output_file
*out
)
4378 for (tem
= list
; tem
; tem
= tem
->next
)
4380 vunits h
= list
->size();
4381 vunits totalh
= h
*npieces
;
4382 vunits y
= (totalh
- h
)/2;
4384 for (tem
= list
; tem
; tem
= tem
->next
) {
4385 tem
->zero_width_tprint(out
);
4388 out
->right(max_width
);
4389 out
->down(totalh
- y
);
4392 void node::tprint(troff_output_file
*)
4396 void node::zero_width_tprint(troff_output_file
*out
)
4398 int hpos
= out
->get_hpos();
4399 int vpos
= out
->get_vpos();
4401 out
->moveto(hpos
, vpos
);
4404 void space_node::tprint(troff_output_file
*out
)
4406 out
->fill_color(col
);
4410 void hmotion_node::tprint(troff_output_file
*out
)
4412 out
->fill_color(col
);
4416 void space_char_hmotion_node::tprint(troff_output_file
*out
)
4418 out
->fill_color(col
);
4420 // we emit the space width as a negative glyph index
4424 out
->put(-n
.to_units());
4430 void vmotion_node::tprint(troff_output_file
*out
)
4432 out
->fill_color(col
);
4436 void kern_pair_node::tprint(troff_output_file
*out
)
4443 static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
4447 tprint_reverse_node_list(out
, n
->next
);
4451 void dbreak_node::tprint(troff_output_file
*out
)
4453 tprint_reverse_node_list(out
, none
);
4456 void composite_node::tprint(troff_output_file
*out
)
4459 int is_bold
= tf
->get_bold(&bold_offset
);
4460 hunits track_kern
= tf
->get_track_kern();
4461 hunits constant_space
;
4462 int is_constant_spaced
= tf
->get_constant_space(&constant_space
);
4464 if (is_constant_spaced
) {
4466 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4475 int hpos
= out
->get_hpos();
4476 int vpos
= out
->get_vpos();
4477 tprint_reverse_node_list(out
, n
);
4478 out
->moveto(hpos
, vpos
);
4479 out
->right(bold_offset
);
4481 tprint_reverse_node_list(out
, n
);
4482 if (is_constant_spaced
)
4485 out
->right(track_kern
);
4488 node
*make_composite_node(charinfo
*s
, environment
*env
)
4490 int fontno
= env_definite_font(env
);
4492 error("no current font");
4495 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4496 node
*n
= charinfo_to_node_list(s
, env
);
4497 font_size fs
= env
->get_font_size();
4498 int char_height
= env
->get_char_height();
4499 int char_slant
= env
->get_char_slant();
4500 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
,
4502 if (env
->is_composite())
4503 tf
= tf
->get_plain();
4504 return new composite_node(n
, s
, tf
);
4507 node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
4509 int fontno
= env_definite_font(env
);
4511 error("no current font");
4514 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4516 int found
= font_table
[fontno
]->contains(s
);
4518 macro
*mac
= s
->get_macro();
4519 if (mac
&& s
->is_fallback())
4520 return make_composite_node(s
, env
);
4521 if (s
->numbered()) {
4522 if (!no_error_message
)
4523 warning(WARN_CHAR
, "can't find numbered character %1",
4527 special_font_list
*sf
= font_table
[fontno
]->sf
;
4528 while (sf
!= 0 && !found
) {
4531 found
= font_table
[fn
]->contains(s
);
4535 symbol f
= font_table
[fontno
]->get_name();
4536 string
gl(f
.contents());
4538 gl
+= s
->nm
.contents();
4540 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
4541 if (ci
&& ci
->get_macro())
4542 return make_composite_node(ci
, env
);
4545 sf
= global_special_fonts
;
4546 while (sf
!= 0 && !found
) {
4549 found
= font_table
[fn
]->contains(s
);
4554 if (mac
&& s
->is_special())
4555 return make_composite_node(s
, env
);
4557 for (fn
= 0; fn
< font_table_size
; fn
++)
4559 && font_table
[fn
]->is_special()
4560 && font_table
[fn
]->contains(s
)) {
4566 if (!no_error_message
&& s
->first_time_not_found()) {
4567 unsigned char input_code
= s
->get_ascii_code();
4568 if (input_code
!= 0) {
4569 if (csgraph(input_code
))
4570 warning(WARN_CHAR
, "can't find character `%1'", input_code
);
4572 warning(WARN_CHAR
, "can't find character with input code %1",
4575 else if (s
->nm
.contents())
4576 warning(WARN_CHAR
, "can't find special character `%1'",
4582 font_size fs
= env
->get_font_size();
4583 int char_height
= env
->get_char_height();
4584 int char_slant
= env
->get_char_slant();
4585 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
4586 if (env
->is_composite())
4587 tf
= tf
->get_plain();
4588 color
*gcol
= env
->get_glyph_color();
4589 color
*fcol
= env
->get_fill_color();
4590 return new glyph_node(s
, tf
, gcol
, fcol
);
4593 node
*make_node(charinfo
*ci
, environment
*env
)
4595 switch (ci
->get_special_translation()) {
4596 case charinfo::TRANSLATE_SPACE
:
4597 return new space_char_hmotion_node(env
->get_space_width(),
4598 env
->get_fill_color());
4599 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4600 return new unbreakable_space_node(env
->get_space_width(),
4601 env
->get_fill_color());
4602 case charinfo::TRANSLATE_DUMMY
:
4603 return new dummy_node
;
4604 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4605 error("translation to \\% ignored in this context");
4608 charinfo
*tem
= ci
->get_translation();
4611 macro
*mac
= ci
->get_macro();
4612 if (mac
&& ci
->is_normal())
4613 return make_composite_node(ci
, env
);
4615 return make_glyph_node(ci
, env
);
4618 int character_exists(charinfo
*ci
, environment
*env
)
4620 if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
4622 charinfo
*tem
= ci
->get_translation();
4625 if (ci
->get_macro())
4627 node
*nd
= make_glyph_node(ci
, env
, 1);
4635 node
*node::add_char(charinfo
*ci
, environment
*env
,
4636 hunits
*widthp
, int *spacep
)
4639 switch (ci
->get_special_translation()) {
4640 case charinfo::TRANSLATE_SPACE
:
4641 res
= new space_char_hmotion_node(env
->get_space_width(),
4642 env
->get_fill_color(), this);
4643 *widthp
+= res
->width();
4645 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4646 res
= new unbreakable_space_node(env
->get_space_width(),
4647 env
->get_fill_color(), this);
4648 res
->freeze_space();
4649 *widthp
+= res
->width();
4650 *spacep
+= res
->nspaces();
4652 case charinfo::TRANSLATE_DUMMY
:
4653 return new dummy_node(this);
4654 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4655 return add_discretionary_hyphen();
4657 charinfo
*tem
= ci
->get_translation();
4660 macro
*mac
= ci
->get_macro();
4661 if (mac
&& ci
->is_normal()) {
4662 res
= make_composite_node(ci
, env
);
4665 *widthp
+= res
->width();
4671 node
*gn
= make_glyph_node(ci
, env
);
4675 hunits old_width
= width();
4676 node
*p
= gn
->merge_self(this);
4678 *widthp
+= gn
->width();
4683 *widthp
+= p
->width() - old_width
;
4689 if (ci
->can_break_before())
4691 if (ci
->can_break_after())
4694 node
*next1
= res
->next
;
4696 res
= new break_char_node(res
, break_code
, env
->get_fill_color(), next1
);
4704 int same_node(node
*n1
, node
*n2
)
4708 return n1
->type() == n2
->type() && n1
->same(n2
);
4716 int same_node_list(node
*n1
, node
*n2
)
4719 if (n1
->type() != n2
->type() || !n1
->same(n2
))
4727 int extra_size_node::same(node
*nd
)
4729 return n
== ((extra_size_node
*)nd
)->n
;
4732 const char *extra_size_node::type()
4734 return "extra_size_node";
4737 int extra_size_node::force_tprint()
4742 int vertical_size_node::same(node
*nd
)
4744 return n
== ((vertical_size_node
*)nd
)->n
;
4747 const char *vertical_size_node::type()
4749 return "vertical_size_node";
4752 int vertical_size_node::set_unformat_flag()
4757 int vertical_size_node::force_tprint()
4762 int hmotion_node::same(node
*nd
)
4764 return n
== ((hmotion_node
*)nd
)->n
4765 && col
== ((hmotion_node
*)nd
)->col
;
4768 const char *hmotion_node::type()
4770 return "hmotion_node";
4773 int hmotion_node::set_unformat_flag()
4779 int hmotion_node::force_tprint()
4784 node
*hmotion_node::add_self(node
*nd
, hyphen_list
**p
)
4787 hyphen_list
*pp
= *p
;
4793 hyphen_list
*hmotion_node::get_hyphen_list(hyphen_list
*tail
, int *)
4795 return new hyphen_list(0, tail
);
4798 int space_char_hmotion_node::same(node
*nd
)
4800 return n
== ((space_char_hmotion_node
*)nd
)->n
4801 && col
== ((space_char_hmotion_node
*)nd
)->col
;
4804 const char *space_char_hmotion_node::type()
4806 return "space_char_hmotion_node";
4809 int space_char_hmotion_node::force_tprint()
4814 node
*space_char_hmotion_node::add_self(node
*nd
, hyphen_list
**p
)
4817 hyphen_list
*pp
= *p
;
4823 hyphen_list
*space_char_hmotion_node::get_hyphen_list(hyphen_list
*tail
,
4826 return new hyphen_list(0, tail
);
4829 int vmotion_node::same(node
*nd
)
4831 return n
== ((vmotion_node
*)nd
)->n
4832 && col
== ((vmotion_node
*)nd
)->col
;
4835 const char *vmotion_node::type()
4837 return "vmotion_node";
4840 int vmotion_node::force_tprint()
4845 int hline_node::same(node
*nd
)
4847 return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
4850 const char *hline_node::type()
4852 return "hline_node";
4855 int hline_node::force_tprint()
4860 int vline_node::same(node
*nd
)
4862 return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
4865 const char *vline_node::type()
4867 return "vline_node";
4870 int vline_node::force_tprint()
4875 int dummy_node::same(node
* /*nd*/)
4880 const char *dummy_node::type()
4882 return "dummy_node";
4885 int dummy_node::force_tprint()
4890 int transparent_dummy_node::same(node
* /*nd*/)
4895 const char *transparent_dummy_node::type()
4897 return "transparent_dummy_node";
4900 int transparent_dummy_node::force_tprint()
4905 int transparent_dummy_node::ends_sentence()
4910 int zero_width_node::same(node
*nd
)
4912 return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
4915 const char *zero_width_node::type()
4917 return "zero_width_node";
4920 int zero_width_node::force_tprint()
4925 int italic_corrected_node::same(node
*nd
)
4927 return (x
== ((italic_corrected_node
*)nd
)->x
4928 && same_node(n
, ((italic_corrected_node
*)nd
)->n
));
4931 const char *italic_corrected_node::type()
4933 return "italic_corrected_node";
4936 int italic_corrected_node::force_tprint()
4941 left_italic_corrected_node::left_italic_corrected_node(node
*xx
)
4946 left_italic_corrected_node::~left_italic_corrected_node()
4951 node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
4954 hunits lic
= gn
->left_italic_correction();
4955 if (!lic
.is_zero()) {
4962 node
*nd
= n
->merge_glyph_node(gn
);
4965 x
= n
->left_italic_correction();
4972 node
*left_italic_corrected_node::copy()
4974 left_italic_corrected_node
*nd
= new left_italic_corrected_node
;
4982 void left_italic_corrected_node::tprint(troff_output_file
*out
)
4990 const char *left_italic_corrected_node::type()
4992 return "left_italic_corrected_node";
4995 int left_italic_corrected_node::force_tprint()
5000 int left_italic_corrected_node::same(node
*nd
)
5002 return (x
== ((left_italic_corrected_node
*)nd
)->x
5003 && same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
5006 void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
5009 n
->ascii_print(out
);
5012 hunits
left_italic_corrected_node::width()
5014 return n
? n
->width() + x
: H0
;
5017 void left_italic_corrected_node::vertical_extent(vunits
*minimum
,
5021 n
->vertical_extent(minimum
, maximum
);
5023 node::vertical_extent(minimum
, maximum
);
5026 hunits
left_italic_corrected_node::skew()
5028 return n
? n
->skew() + x
/2 : H0
;
5031 hunits
left_italic_corrected_node::subscript_correction()
5033 return n
? n
->subscript_correction() : H0
;
5036 hunits
left_italic_corrected_node::italic_correction()
5038 return n
? n
->italic_correction() : H0
;
5041 int left_italic_corrected_node::ends_sentence()
5043 return n
? n
->ends_sentence() : 0;
5046 int left_italic_corrected_node::overlaps_horizontally()
5048 return n
? n
->overlaps_horizontally() : 0;
5051 int left_italic_corrected_node::overlaps_vertically()
5053 return n
? n
->overlaps_vertically() : 0;
5056 node
*left_italic_corrected_node::last_char_node()
5058 return n
? n
->last_char_node() : 0;
5061 tfont
*left_italic_corrected_node::get_tfont()
5063 return n
? n
->get_tfont() : 0;
5066 hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
5069 return n
->get_hyphenation_type();
5071 return HYPHEN_MIDDLE
;
5074 hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
5077 return n
? n
->get_hyphen_list(tail
, count
) : tail
;
5080 node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
5083 nd
= new left_italic_corrected_node(nd
);
5084 nd
= n
->add_self(nd
, p
);
5091 int left_italic_corrected_node::character_type()
5093 return n
? n
->character_type() : 0;
5096 int overstrike_node::same(node
*nd
)
5098 return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
5101 const char *overstrike_node::type()
5103 return "overstrike_node";
5106 int overstrike_node::force_tprint()
5111 node
*overstrike_node::add_self(node
*n
, hyphen_list
**p
)
5114 hyphen_list
*pp
= *p
;
5120 hyphen_list
*overstrike_node::get_hyphen_list(hyphen_list
*tail
, int *)
5122 return new hyphen_list(0, tail
);
5125 int bracket_node::same(node
*nd
)
5127 return same_node_list(list
, ((bracket_node
*)nd
)->list
);
5130 const char *bracket_node::type()
5132 return "bracket_node";
5135 int bracket_node::force_tprint()
5140 int composite_node::same(node
*nd
)
5142 return ci
== ((composite_node
*)nd
)->ci
5143 && same_node_list(n
, ((composite_node
*)nd
)->n
);
5146 const char *composite_node::type()
5148 return "composite_node";
5151 int composite_node::force_tprint()
5156 int glyph_node::same(node
*nd
)
5158 return ci
== ((glyph_node
*)nd
)->ci
5159 && tf
== ((glyph_node
*)nd
)->tf
5160 && gcol
== ((glyph_node
*)nd
)->gcol
5161 && fcol
== ((glyph_node
*)nd
)->fcol
;
5164 const char *glyph_node::type()
5166 return "glyph_node";
5169 int glyph_node::force_tprint()
5174 int ligature_node::same(node
*nd
)
5176 return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
5177 && same_node(n2
, ((ligature_node
*)nd
)->n2
)
5178 && glyph_node::same(nd
));
5181 const char *ligature_node::type()
5183 return "ligature_node";
5186 int ligature_node::force_tprint()
5191 int kern_pair_node::same(node
*nd
)
5193 return (amount
== ((kern_pair_node
*)nd
)->amount
5194 && same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
5195 && same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
5198 const char *kern_pair_node::type()
5200 return "kern_pair_node";
5203 int kern_pair_node::force_tprint()
5208 int dbreak_node::same(node
*nd
)
5210 return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
5211 && same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
5212 && same_node_list(post
, ((dbreak_node
*)nd
)->post
));
5215 const char *dbreak_node::type()
5217 return "dbreak_node";
5220 int dbreak_node::force_tprint()
5225 int break_char_node::same(node
*nd
)
5227 return break_code
== ((break_char_node
*)nd
)->break_code
5228 && col
== ((break_char_node
*)nd
)->col
5229 && same_node(ch
, ((break_char_node
*)nd
)->ch
);
5232 const char *break_char_node::type()
5234 return "break_char_node";
5237 int break_char_node::force_tprint()
5242 int line_start_node::same(node
* /*nd*/)
5247 const char *line_start_node::type()
5249 return "line_start_node";
5252 int line_start_node::force_tprint()
5257 int space_node::same(node
*nd
)
5259 return n
== ((space_node
*)nd
)->n
5260 && set
== ((space_node
*)nd
)->set
5261 && col
== ((space_node
*)nd
)->col
;
5264 const char *space_node::type()
5266 return "space_node";
5269 int word_space_node::same(node
*nd
)
5271 return n
== ((word_space_node
*)nd
)->n
5272 && set
== ((word_space_node
*)nd
)->set
5273 && col
== ((word_space_node
*)nd
)->col
;
5276 const char *word_space_node::type()
5278 return "word_space_node";
5281 int word_space_node::force_tprint()
5286 void unbreakable_space_node::tprint(troff_output_file
*out
)
5288 out
->fill_color(col
);
5290 // we emit the space width as a negative glyph index
5294 out
->put(-n
.to_units());
5300 int unbreakable_space_node::same(node
*nd
)
5302 return n
== ((unbreakable_space_node
*)nd
)->n
5303 && set
== ((unbreakable_space_node
*)nd
)->set
5304 && col
== ((unbreakable_space_node
*)nd
)->col
;
5307 const char *unbreakable_space_node::type()
5309 return "unbreakable_space_node";
5312 node
*unbreakable_space_node::add_self(node
*nd
, hyphen_list
**p
)
5315 hyphen_list
*pp
= *p
;
5321 hyphen_list
*unbreakable_space_node::get_hyphen_list(hyphen_list
*tail
, int *)
5323 return new hyphen_list(0, tail
);
5326 int diverted_space_node::same(node
*nd
)
5328 return n
== ((diverted_space_node
*)nd
)->n
;
5331 const char *diverted_space_node::type()
5333 return "diverted_space_node";
5336 int diverted_space_node::force_tprint()
5341 int diverted_copy_file_node::same(node
*nd
)
5343 return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
5346 const char *diverted_copy_file_node::type()
5348 return "diverted_copy_file_node";
5351 int diverted_copy_file_node::force_tprint()
5356 // Grow the font_table so that its size is > n.
5358 static void grow_font_table(int n
)
5360 assert(n
>= font_table_size
);
5361 font_info
**old_font_table
= font_table
;
5362 int old_font_table_size
= font_table_size
;
5363 font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
5364 if (font_table_size
<= n
)
5365 font_table_size
= n
+ 10;
5366 font_table
= new font_info
*[font_table_size
];
5367 if (old_font_table_size
)
5368 memcpy(font_table
, old_font_table
,
5369 old_font_table_size
*sizeof(font_info
*));
5370 a_delete old_font_table
;
5371 for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
5375 dictionary
font_translation_dictionary(17);
5377 static symbol
get_font_translation(symbol nm
)
5379 void *p
= font_translation_dictionary
.lookup(nm
);
5380 return p
? symbol((char *)p
) : nm
;
5383 dictionary
font_dictionary(50);
5385 static int mount_font_no_translate(int n
, symbol name
, symbol external_name
)
5388 // We store the address of this char in font_dictionary to indicate
5389 // that we've previously tried to mount the font and failed.
5392 void *p
= font_dictionary
.lookup(external_name
);
5395 fm
= font::load_font(external_name
.contents(), ¬_found
);
5398 warning(WARN_FONT
, "can't find font `%1'", external_name
.contents());
5399 (void)font_dictionary
.lookup(external_name
, &a_char
);
5402 (void)font_dictionary
.lookup(name
, fm
);
5404 else if (p
== &a_char
) {
5406 error("invalid font `%1'", external_name
.contents());
5412 if (n
>= font_table_size
) {
5413 if (n
- font_table_size
> 1000) {
5414 error("font position too much larger than first unused position");
5419 else if (font_table
[n
] != 0)
5420 delete font_table
[n
];
5421 font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
5422 font_family::invalidate_fontno(n
);
5426 int mount_font(int n
, symbol name
, symbol external_name
)
5429 name
= get_font_translation(name
);
5430 if (external_name
.is_null())
5431 external_name
= name
;
5433 external_name
= get_font_translation(external_name
);
5434 return mount_font_no_translate(n
, name
, external_name
);
5437 void mount_style(int n
, symbol name
)
5440 if (n
>= font_table_size
) {
5441 if (n
- font_table_size
> 1000) {
5442 error("font position too much larger than first unused position");
5447 else if (font_table
[n
] != 0)
5448 delete font_table
[n
];
5449 font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
5450 font_family::invalidate_fontno(n
);
5453 /* global functions */
5455 void font_translate()
5457 symbol from
= get_name(1);
5458 if (!from
.is_null()) {
5459 symbol to
= get_name();
5460 if (to
.is_null() || from
== to
)
5461 font_translation_dictionary
.remove(from
);
5463 (void)font_translation_dictionary
.lookup(from
, (void *)to
.contents());
5468 void font_position()
5471 if (get_integer(&n
)) {
5473 error("negative font position");
5475 symbol internal_name
= get_name(1);
5476 if (!internal_name
.is_null()) {
5477 symbol external_name
= get_long_name();
5478 mount_font(n
, internal_name
, external_name
); // ignore error
5485 font_family::font_family(symbol s
)
5486 : map_size(10), nm(s
)
5488 map
= new int[map_size
];
5489 for (int i
= 0; i
< map_size
; i
++)
5493 font_family::~font_family()
5498 int font_family::make_definite(int i
)
5501 if (i
< map_size
&& map
[i
] >= 0)
5504 if (i
< font_table_size
&& font_table
[i
] != 0) {
5505 if (i
>= map_size
) {
5506 int old_map_size
= map_size
;
5512 map
= new int[map_size
];
5513 memcpy(map
, old_map
, old_map_size
*sizeof(int));
5515 for (int j
= old_map_size
; j
< map_size
; j
++)
5518 if (font_table
[i
]->is_style()) {
5519 symbol sty
= font_table
[i
]->get_name();
5520 symbol f
= concat(nm
, sty
);
5522 // don't use symbol_fontno, because that might return a style
5523 // and because we don't want to translate the name
5524 for (n
= 0; n
< font_table_size
; n
++)
5525 if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
5526 && !font_table
[n
]->is_style())
5528 if (n
>= font_table_size
) {
5529 n
= next_available_font_position();
5530 if (!mount_font_no_translate(n
, f
, f
))
5546 dictionary
family_dictionary(5);
5548 font_family
*lookup_family(symbol nm
)
5550 font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
5552 f
= new font_family(nm
);
5553 (void)family_dictionary
.lookup(nm
, f
);
5558 void font_family::invalidate_fontno(int n
)
5560 assert(n
>= 0 && n
< font_table_size
);
5561 dictionary_iterator
iter(family_dictionary
);
5564 while (iter
.get(&nam
, (void **)&fam
)) {
5565 int mapsize
= fam
->map_size
;
5568 for (int i
= 0; i
< mapsize
; i
++)
5569 if (fam
->map
[i
] == n
)
5577 if (get_integer(&n
)) {
5579 error("negative font position");
5581 symbol internal_name
= get_name(1);
5582 if (!internal_name
.is_null())
5583 mount_style(n
, internal_name
);
5589 static int get_fontno()
5593 if (tok
.delimiter()) {
5594 symbol s
= get_name(1);
5596 n
= symbol_fontno(s
);
5598 n
= next_available_font_position();
5599 if (!mount_font(n
, s
))
5602 return curenv
->get_family()->make_definite(n
);
5605 else if (get_integer(&n
)) {
5606 if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
5607 error("bad font number");
5609 return curenv
->get_family()->make_definite(n
);
5614 static int underline_fontno
= 2;
5616 void underline_font()
5618 int n
= get_fontno();
5620 underline_fontno
= n
;
5624 int get_underline_fontno()
5626 return underline_fontno
;
5629 void define_font_special_character()
5631 int n
= get_fontno();
5636 symbol f
= font_table
[n
]->get_name();
5637 do_define_character(CHAR_FONT_SPECIAL
, f
.contents());
5640 void remove_font_special_character()
5642 int n
= get_fontno();
5647 symbol f
= font_table
[n
]->get_name();
5648 while (!tok
.newline() && !tok
.eof()) {
5649 if (!tok
.space() && !tok
.tab()) {
5650 charinfo
*s
= tok
.get_char(1);
5651 string
gl(f
.contents());
5653 gl
+= s
->nm
.contents();
5655 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
5658 macro
*m
= ci
->set_macro(0);
5667 static void read_special_fonts(special_font_list
**sp
)
5669 special_font_list
*s
= *sp
;
5672 special_font_list
*tem
= s
;
5676 special_font_list
**p
= sp
;
5678 int i
= get_fontno();
5680 special_font_list
*tem
= new special_font_list
;
5689 void font_special_request()
5691 int n
= get_fontno();
5693 read_special_fonts(&font_table
[n
]->sf
);
5697 void special_request()
5699 read_special_fonts(&global_special_fonts
);
5703 int next_available_font_position()
5706 for (i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
5711 int symbol_fontno(symbol s
)
5713 s
= get_font_translation(s
);
5714 for (int i
= 0; i
< font_table_size
; i
++)
5715 if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
5720 int is_good_fontno(int n
)
5722 return n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0;
5725 int get_bold_fontno(int n
)
5727 if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
5729 if (font_table
[n
]->get_bold(&offset
))
5730 return offset
.to_units() + 1;
5738 hunits
env_digit_width(environment
*env
)
5740 node
*n
= make_glyph_node(charset_table
['0'], env
);
5742 hunits x
= n
->width();
5750 hunits
env_space_width(environment
*env
)
5752 int fn
= env_definite_font(env
);
5753 font_size fs
= env
->get_font_size();
5754 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5755 return scale(fs
.to_units()/3, env
->get_space_size(), 12);
5757 return font_table
[fn
]->get_space_width(fs
, env
->get_space_size());
5760 hunits
env_sentence_space_width(environment
*env
)
5762 int fn
= env_definite_font(env
);
5763 font_size fs
= env
->get_font_size();
5764 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5765 return scale(fs
.to_units()/3, env
->get_sentence_space_size(), 12);
5767 return font_table
[fn
]->get_space_width(fs
, env
->get_sentence_space_size());
5770 hunits
env_half_narrow_space_width(environment
*env
)
5772 int fn
= env_definite_font(env
);
5773 font_size fs
= env
->get_font_size();
5774 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5777 return font_table
[fn
]->get_half_narrow_space_width(fs
);
5780 hunits
env_narrow_space_width(environment
*env
)
5782 int fn
= env_definite_font(env
);
5783 font_size fs
= env
->get_font_size();
5784 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5787 return font_table
[fn
]->get_narrow_space_width(fs
);
5792 int n
= get_fontno();
5795 if (tok
.delimiter()) {
5796 int f
= get_fontno();
5799 if (has_arg() && get_number(&offset
, 'u') && offset
>= 1)
5800 font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
5802 font_table
[f
]->conditional_unbold(n
);
5807 if (get_number(&offset
, 'u') && offset
>= 1)
5808 font_table
[n
]->set_bold(hunits(offset
- 1));
5810 font_table
[n
]->unbold();
5814 font_table
[n
]->unbold();
5819 track_kerning_function::track_kerning_function() : non_zero(0)
5823 track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
5824 int max_s
, hunits max_a
)
5825 : non_zero(1), min_size(min_s
), min_amount(min_a
), max_size(max_s
),
5830 int track_kerning_function::operator==(const track_kerning_function
&tk
)
5834 && min_size
== tk
.min_size
5835 && min_amount
== tk
.min_amount
5836 && max_size
== tk
.max_size
5837 && max_amount
== tk
.max_amount
);
5839 return !tk
.non_zero
;
5842 int track_kerning_function::operator!=(const track_kerning_function
&tk
)
5845 return (!tk
.non_zero
5846 || min_size
!= tk
.min_size
5847 || min_amount
!= tk
.min_amount
5848 || max_size
!= tk
.max_size
5849 || max_amount
!= tk
.max_amount
);
5854 hunits
track_kerning_function::compute(int size
)
5857 if (max_size
<= min_size
)
5859 else if (size
<= min_size
)
5861 else if (size
>= max_size
)
5864 return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
5865 + scale(min_amount
, max_size
- size
, max_size
- min_size
));
5873 int n
= get_fontno();
5876 hunits min_a
, max_a
;
5878 && get_number(&min_s
, 'z')
5879 && get_hunits(&min_a
, 'p')
5880 && get_number(&max_s
, 'z')
5881 && get_hunits(&max_a
, 'p')) {
5882 track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
5883 font_table
[n
]->set_track_kern(tk
);
5886 track_kerning_function tk
;
5887 font_table
[n
]->set_track_kern(tk
);
5893 void constant_space()
5895 int n
= get_fontno();
5898 if (!has_arg() || !get_integer(&x
))
5899 font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
5901 if (!has_arg() || !get_number(&y
, 'z'))
5902 font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
5904 font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
5916 if (has_arg() && get_integer(&lig
) && lig
>= 0 && lig
<= 2)
5917 global_ligature_mode
= lig
;
5919 global_ligature_mode
= 1;
5926 if (has_arg() && get_integer(&k
))
5927 global_kern_mode
= k
!= 0;
5929 global_kern_mode
= 1;
5933 void set_soft_hyphen_char()
5935 soft_hyphen_char
= get_optional_char();
5936 if (!soft_hyphen_char
)
5937 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);
5943 if (suppress_output_flag
)
5944 the_output
= new suppress_output_file
;
5945 else if (ascii_output_flag
)
5946 the_output
= new ascii_output_file
;
5948 the_output
= new troff_output_file
;
5951 class next_available_font_position_reg
: public reg
{
5953 const char *get_string();
5956 const char *next_available_font_position_reg::get_string()
5958 return i_to_a(next_available_font_position());
5961 class printing_reg
: public reg
{
5963 const char *get_string();
5966 const char *printing_reg::get_string()
5969 return the_output
->is_printing() ? "1" : "0";
5974 void init_node_requests()
5976 init_request("bd", bold_font
);
5977 init_request("cs", constant_space
);
5978 init_request("fp", font_position
);
5979 init_request("fschar", define_font_special_character
);
5980 init_request("fspecial", font_special_request
);
5981 init_request("ftr", font_translate
);
5982 init_request("kern", kern_request
);
5983 init_request("lg", ligature
);
5984 init_request("rfschar", remove_font_special_character
);
5985 init_request("shc", set_soft_hyphen_char
);
5986 init_request("special", special_request
);
5987 init_request("sty", style
);
5988 init_request("tkf", track_kern
);
5989 init_request("uf", underline_font
);
5990 number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
5991 number_reg_dictionary
.define(".kern",
5992 new constant_int_reg(&global_kern_mode
));
5993 number_reg_dictionary
.define(".lg",
5994 new constant_int_reg(&global_ligature_mode
));
5995 number_reg_dictionary
.define(".P", new printing_reg
);
5996 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);