2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #include "dictionary.h"
35 symbol
HYPHEN_SYMBOL("hy");
37 // Character used when a hyphen is inserted at a line break.
38 static charinfo
*soft_hyphen_char
;
40 enum constant_space_type
{
42 CONSTANT_SPACE_RELATIVE
,
43 CONSTANT_SPACE_ABSOLUTE
46 struct special_font_list
{
48 special_font_list
*next
;
51 special_font_list
*global_special_fonts
;
52 static int global_ligature_mode
= 1;
53 static int global_kern_mode
= 1;
55 class track_kerning_function
{
62 track_kerning_function();
63 track_kerning_function(units
, hunits
, units
, hunits
);
64 int operator==(const track_kerning_function
&);
65 int operator!=(const track_kerning_function
&);
66 hunits
compute(int point_size
);
69 // embolden fontno when this is the current font
71 struct conditional_bold
{
72 conditional_bold
*next
;
75 conditional_bold(int, hunits
, conditional_bold
* = 0);
91 track_kerning_function track_kern
;
92 constant_space_type is_constant_spaced
;
94 int last_ligature_mode
;
96 conditional_bold
*cond_bold_list
;
99 special_font_list
*sf
;
101 font_info(symbol nm
, int n
, symbol enm
, font
*f
);
102 int contains(charinfo
*);
103 void set_bold(hunits
);
105 void set_conditional_bold(int, hunits
);
106 void conditional_unbold(int);
107 void set_track_kern(track_kerning_function
&);
108 void set_constant_space(constant_space_type
, units
= 0);
109 int is_named(symbol
);
111 tfont
*get_tfont(font_size
, int, int, int);
112 hunits
get_space_width(font_size
, int);
113 hunits
get_narrow_space_width(font_size
);
114 hunits
get_half_narrow_space_width(font_size
);
115 int get_bold(hunits
*);
127 char is_constant_spaced
;
131 hunits track_kern
; // add this to the width
132 hunits constant_space_width
;
136 tfont_spec(symbol nm
, int pos
, font
*, font_size
, int, int);
138 int operator==(const tfont_spec
&);
139 friend tfont
*font_info::get_tfont(font_size fs
, int, int, int);
142 class tfont
: public tfont_spec
{
143 static tfont
*tfont_list
;
145 tfont
*plain_version
;
148 int contains(charinfo
*);
149 hunits
get_width(charinfo
*c
);
150 int get_bold(hunits
*);
151 int get_constant_space(hunits
*);
152 hunits
get_track_kern();
154 font_size
get_size();
156 charinfo
*get_lig(charinfo
*c1
, charinfo
*c2
);
157 int get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
);
158 int get_input_position();
159 int get_character_type(charinfo
*);
162 vunits
get_char_height(charinfo
*);
163 vunits
get_char_depth(charinfo
*);
164 hunits
get_char_skew(charinfo
*);
165 hunits
get_italic_correction(charinfo
*);
166 hunits
get_left_italic_correction(charinfo
*);
167 hunits
get_subscript_correction(charinfo
*);
168 friend tfont
*make_tfont(tfont_spec
&);
171 inline int env_definite_font(environment
*env
)
173 return env
->get_family()->make_definite(env
->get_font());
176 static void invalidate_fontno(int n
);
178 /* font_info functions */
180 static font_info
**font_table
= 0;
181 static int font_table_size
= 0;
183 font_info::font_info(symbol nm
, int n
, symbol enm
, font
*f
)
184 : internal_name(nm
), external_name(enm
), fm(f
), number(n
),
185 is_constant_spaced(CONSTANT_SPACE_NONE
),
186 sf(0), is_bold(0), cond_bold_list(0),
187 last_ligature_mode(1), last_kern_mode(1),
188 last_tfont(0), last_size(0)
192 inline int font_info::contains(charinfo
*ci
)
194 return fm
!= 0 && fm
->contains(ci
->get_index());
197 inline int font_info::is_special()
199 return fm
!= 0 && fm
->is_special();
202 inline int font_info::is_style()
207 // this is the current_font, fontno is where we found the character,
208 // presumably a special font
210 tfont
*font_info::get_tfont(font_size fs
, int height
, int slant
, int fontno
)
212 if (last_tfont
== 0 || fs
!= last_size
213 || height
!= last_height
|| slant
!= last_slant
214 || global_ligature_mode
!= last_ligature_mode
215 || global_kern_mode
!= last_kern_mode
216 || fontno
!= number
) {
217 font_info
*f
= font_table
[fontno
];
218 tfont_spec
spec(f
->external_name
, f
->number
, f
->fm
, fs
, height
, slant
);
219 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
220 if (p
->fontno
== fontno
) {
222 spec
.bold_offset
= p
->offset
;
225 if (!spec
.is_bold
&& is_bold
) {
227 spec
.bold_offset
= bold_offset
;
229 spec
.track_kern
= track_kern
.compute(fs
.to_scaled_points());
230 spec
.ligature_mode
= global_ligature_mode
;
231 spec
.kern_mode
= global_kern_mode
;
232 switch (is_constant_spaced
) {
233 case CONSTANT_SPACE_NONE
:
235 case CONSTANT_SPACE_ABSOLUTE
:
236 spec
.is_constant_spaced
= 1;
237 spec
.constant_space_width
= constant_space
;
239 case CONSTANT_SPACE_RELATIVE
:
240 spec
.is_constant_spaced
= 1;
241 spec
.constant_space_width
242 = scale(constant_space
*fs
.to_scaled_points(),
249 if (fontno
!= number
)
250 return make_tfont(spec
);
251 last_tfont
= make_tfont(spec
);
253 last_height
= height
;
255 last_ligature_mode
= global_ligature_mode
;
256 last_kern_mode
= global_kern_mode
;
261 int font_info::get_bold(hunits
*res
)
271 void font_info::unbold()
279 void font_info::set_bold(hunits offset
)
281 if (!is_bold
|| offset
!= bold_offset
) {
283 bold_offset
= offset
;
288 void font_info::set_conditional_bold(int fontno
, hunits offset
)
290 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
291 if (p
->fontno
== fontno
) {
292 if (offset
!= p
->offset
) {
298 cond_bold_list
= new conditional_bold(fontno
, offset
, cond_bold_list
);
301 conditional_bold::conditional_bold(int f
, hunits h
, conditional_bold
*x
)
302 : fontno(f
), offset(h
), next(x
)
306 void font_info::conditional_unbold(int fontno
)
308 for (conditional_bold
**p
= &cond_bold_list
; *p
; p
= &(*p
)->next
)
309 if ((*p
)->fontno
== fontno
) {
310 conditional_bold
*tem
= *p
;
318 void font_info::set_constant_space(constant_space_type type
, units x
)
320 if (type
!= is_constant_spaced
321 || (type
!= CONSTANT_SPACE_NONE
&& x
!= constant_space
)) {
323 is_constant_spaced
= type
;
328 void font_info::set_track_kern(track_kerning_function
&tk
)
330 if (track_kern
!= tk
) {
336 void font_info::flush()
341 int font_info::is_named(symbol s
)
343 return internal_name
== s
;
346 symbol
font_info::get_name()
348 return internal_name
;
351 hunits
font_info::get_space_width(font_size fs
, int space_size
)
353 if (is_constant_spaced
== CONSTANT_SPACE_NONE
)
354 return scale(hunits(fm
->get_space_width(fs
.to_scaled_points())),
356 else if (is_constant_spaced
== CONSTANT_SPACE_ABSOLUTE
)
357 return constant_space
;
359 return scale(constant_space
*fs
.to_scaled_points(),
360 units_per_inch
, 36*72*sizescale
);
363 hunits
font_info::get_narrow_space_width(font_size fs
)
365 charinfo
*ci
= get_charinfo(symbol("|"));
366 if (fm
->contains(ci
->get_index()))
367 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
369 return hunits(fs
.to_units()/6);
372 hunits
font_info::get_half_narrow_space_width(font_size fs
)
374 charinfo
*ci
= get_charinfo(symbol("^"));
375 if (fm
->contains(ci
->get_index()))
376 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
378 return hunits(fs
.to_units()/12);
383 tfont_spec::tfont_spec(symbol nm
, int n
, font
*f
,
384 font_size s
, int h
, int sl
)
385 : name(nm
), input_position(n
), fm(f
), size(s
),
386 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
389 if (height
== size
.to_scaled_points())
393 int tfont_spec::operator==(const tfont_spec
&spec
)
397 && input_position
== spec
.input_position
399 && height
== spec
.height
400 && slant
== spec
.slant
402 ? (spec
.is_bold
&& bold_offset
== spec
.bold_offset
)
404 && track_kern
== spec
.track_kern
405 && (is_constant_spaced
406 ? (spec
.is_constant_spaced
407 && constant_space_width
== spec
.constant_space_width
)
408 : !spec
.is_constant_spaced
)
409 && ligature_mode
== spec
.ligature_mode
410 && kern_mode
== spec
.kern_mode
)
416 tfont_spec
tfont_spec::plain()
418 return tfont_spec(name
, input_position
, fm
, size
, height
, slant
);
421 hunits
tfont::get_width(charinfo
*c
)
423 if (is_constant_spaced
)
424 return constant_space_width
;
426 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
427 + track_kern
+ bold_offset
);
429 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points())) + track_kern
);
432 vunits
tfont::get_char_height(charinfo
*c
)
434 vunits v
= fm
->get_height(c
->get_index(), size
.to_scaled_points());
435 if (height
!= 0 && height
!= size
.to_scaled_points())
436 return scale(v
, height
, size
.to_scaled_points());
441 vunits
tfont::get_char_depth(charinfo
*c
)
443 vunits v
= fm
->get_depth(c
->get_index(), size
.to_scaled_points());
444 if (height
!= 0 && height
!= size
.to_scaled_points())
445 return scale(v
, height
, size
.to_scaled_points());
450 hunits
tfont::get_char_skew(charinfo
*c
)
452 return hunits(fm
->get_skew(c
->get_index(), size
.to_scaled_points(), slant
));
455 hunits
tfont::get_italic_correction(charinfo
*c
)
457 return hunits(fm
->get_italic_correction(c
->get_index(), size
.to_scaled_points()));
460 hunits
tfont::get_left_italic_correction(charinfo
*c
)
462 return hunits(fm
->get_left_italic_correction(c
->get_index(),
463 size
.to_scaled_points()));
466 hunits
tfont::get_subscript_correction(charinfo
*c
)
468 return hunits(fm
->get_subscript_correction(c
->get_index(),
469 size
.to_scaled_points()));
472 inline int tfont::get_input_position()
474 return input_position
;
477 inline int tfont::contains(charinfo
*ci
)
479 return fm
->contains(ci
->get_index());
482 inline int tfont::get_character_type(charinfo
*ci
)
484 return fm
->get_character_type(ci
->get_index());
487 inline int tfont::get_bold(hunits
*res
)
497 inline int tfont::get_constant_space(hunits
*res
)
499 if (is_constant_spaced
) {
500 *res
= constant_space_width
;
507 inline hunits
tfont::get_track_kern()
512 inline tfont
*tfont::get_plain()
514 return plain_version
;
517 inline font_size
tfont::get_size()
522 inline symbol
tfont::get_name()
527 inline int tfont::get_height()
532 inline int tfont::get_slant()
537 symbol
SYMBOL_ff("ff");
538 symbol
SYMBOL_fi("fi");
539 symbol
SYMBOL_fl("fl");
540 symbol
SYMBOL_Fi("Fi");
541 symbol
SYMBOL_Fl("Fl");
543 charinfo
*tfont::get_lig(charinfo
*c1
, charinfo
*c2
)
545 if (ligature_mode
== 0)
548 if (c1
->get_ascii_code() == 'f') {
549 switch (c2
->get_ascii_code()) {
551 if (fm
->has_ligature(font::LIG_ff
))
552 ci
= get_charinfo(SYMBOL_ff
);
555 if (fm
->has_ligature(font::LIG_fi
))
556 ci
= get_charinfo(SYMBOL_fi
);
559 if (fm
->has_ligature(font::LIG_fl
))
560 ci
= get_charinfo(SYMBOL_fl
);
564 else if (ligature_mode
!= 2 && c1
->nm
== SYMBOL_ff
) {
565 switch (c2
->get_ascii_code()) {
567 if (fm
->has_ligature(font::LIG_ffi
))
568 ci
= get_charinfo(SYMBOL_Fi
);
571 if (fm
->has_ligature(font::LIG_ffl
))
572 ci
= get_charinfo(SYMBOL_Fl
);
576 if (ci
!= 0 && fm
->contains(ci
->get_index()))
581 inline int tfont::get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
)
586 int n
= fm
->get_kern(c1
->get_index(),
588 size
.to_scaled_points());
598 tfont
*make_tfont(tfont_spec
&spec
)
600 for (tfont
*p
= tfont::tfont_list
; p
; p
= p
->next
)
603 return new tfont(spec
);
606 tfont
*tfont::tfont_list
= 0;
608 tfont::tfont(tfont_spec
&spec
) : tfont_spec(spec
)
612 tfont_spec plain_spec
= plain();
613 for (tfont
*p
= tfont_list
; p
; p
= p
->next
)
614 if (*p
== plain_spec
) {
619 plain_version
= new tfont(plain_spec
);
624 class real_output_file
: public output_file
{
627 virtual void really_transparent_char(unsigned char) = 0;
628 virtual void really_print_line(hunits x
, vunits y
, node
*n
,
629 vunits before
, vunits after
) = 0;
630 virtual void really_begin_page(int pageno
, vunits page_length
) = 0;
631 virtual void really_copy_file(hunits x
, vunits y
, const char *filename
);
638 void transparent_char(unsigned char);
639 void print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
);
640 void begin_page(int pageno
, vunits page_length
);
642 void copy_file(hunits x
, vunits y
, const char *filename
);
645 class suppress_output_file
: public real_output_file
{
647 suppress_output_file();
648 void really_transparent_char(unsigned char);
649 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
);
650 void really_begin_page(int pageno
, vunits page_length
);
653 class ascii_output_file
: public real_output_file
{
656 void really_transparent_char(unsigned char);
657 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
);
658 void really_begin_page(int pageno
, vunits page_length
);
659 void outc(unsigned char c
);
660 void outs(const char *s
);
663 void ascii_output_file::outc(unsigned char c
)
668 void ascii_output_file::outs(const char *s
)
678 class troff_output_file
: public real_output_file
{
687 tfont
*current_tfont
;
688 int current_font_number
;
689 symbol
*font_position
;
691 enum { TBUF_SIZE
= 256 };
692 char tbuf
[TBUF_SIZE
];
698 void put(unsigned char c
);
700 void put(const char *s
);
701 void set_font(tfont
*tf
);
705 ~troff_output_file();
706 void put_char(charinfo
*ci
, tfont
*tf
);
707 void put_char_width(charinfo
*ci
, tfont
*tf
, hunits w
, hunits k
);
710 void moveto(hunits
, vunits
);
711 void start_special();
712 void special_char(unsigned char c
);
715 void really_transparent_char(unsigned char c
);
716 void really_print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
);
717 void really_begin_page(int pageno
, vunits page_length
);
718 void really_copy_file(hunits x
, vunits y
, const char *filename
);
719 void draw(char, hvpair
*, int, font_size
);
720 int get_hpos() { return hpos
; }
721 int get_vpos() { return vpos
; }
724 static void put_string(const char *s
, FILE *fp
)
726 for (; *s
!= '\0'; ++s
)
730 inline void troff_output_file::put(char c
)
735 inline void troff_output_file::put(unsigned char c
)
740 inline void troff_output_file::put(const char *s
)
745 inline void troff_output_file::put(int i
)
747 put_string(itoa(i
), fp
);
750 void troff_output_file::start_special()
757 void troff_output_file::special_char(unsigned char c
)
764 void troff_output_file::end_special()
769 inline void troff_output_file::moveto(hunits h
, vunits v
)
775 void troff_output_file::really_print_line(hunits x
, vunits y
, node
*n
,
776 vunits before
, vunits after
)
784 // This ensures that transparent throughput will have a more predictable
790 put(before
.to_units());
792 put(after
.to_units());
796 inline void troff_output_file::word_marker()
802 inline void troff_output_file::right(hunits n
)
804 hpos
+= n
.to_units();
807 inline void troff_output_file::down(vunits n
)
809 vpos
+= n
.to_units();
812 void troff_output_file::do_motion()
823 if (hpos
!= output_hpos
) {
824 units n
= hpos
- output_hpos
;
825 if (n
> 0 && n
< hpos
) {
835 if (vpos
!= output_vpos
) {
836 units n
= vpos
- output_vpos
;
837 if (n
> 0 && n
< vpos
) {
853 void troff_output_file::flush_tbuf()
864 for (int i
= 0; i
< tbuf_len
; i
++)
870 void troff_output_file::put_char_width(charinfo
*ci
, tfont
*tf
, hunits w
,
873 if (tf
!= current_tfont
) {
877 char c
= ci
->get_ascii_code();
878 int kk
= k
.to_units();
882 if (ci
->numbered()) {
884 put(ci
->get_number());
888 const char *s
= ci
->nm
.contents();
897 hpos
+= w
.to_units() + kk
;
899 else if (tcommand_flag
) {
900 if (tbuf_len
> 0 && hpos
== output_hpos
&& vpos
== output_vpos
902 && tbuf_len
< TBUF_SIZE
) {
903 tbuf
[tbuf_len
++] = c
;
904 output_hpos
+= w
.to_units() + kk
;
910 tbuf
[tbuf_len
++] = c
;
911 output_hpos
+= w
.to_units() + kk
;
917 int n
= hpos
- output_hpos
;
918 if (vpos
== output_vpos
&& n
> 0 && n
< 100 && !force_motion
) {
919 put(char(n
/10 + '0'));
920 put(char(n
%10 + '0'));
929 hpos
+= w
.to_units() + kk
;
933 void troff_output_file::put_char(charinfo
*ci
, tfont
*tf
)
936 if (tf
!= current_tfont
)
938 char c
= ci
->get_ascii_code();
941 if (ci
->numbered()) {
943 put(ci
->get_number());
947 const char *s
= ci
->nm
.contents();
958 int n
= hpos
- output_hpos
;
959 if (vpos
== output_vpos
&& n
> 0 && n
< 100) {
960 put(char(n
/10 + '0'));
961 put(char(n
%10 + '0'));
973 void troff_output_file::set_font(tfont
*tf
)
975 if (current_tfont
== tf
)
977 int n
= tf
->get_input_position();
978 symbol nm
= tf
->get_name();
979 if (n
>= nfont_positions
|| font_position
[n
] != nm
) {
985 if (n
>= nfont_positions
) {
986 int old_nfont_positions
= nfont_positions
;
987 symbol
*old_font_position
= font_position
;
988 nfont_positions
*= 3;
989 nfont_positions
/= 2;
990 if (nfont_positions
<= n
)
991 nfont_positions
= n
+ 10;
992 font_position
= new symbol
[nfont_positions
];
993 memcpy(font_position
, old_font_position
,
994 old_nfont_positions
*sizeof(symbol
));
995 a_delete old_font_position
;
997 font_position
[n
] = nm
;
999 if (current_font_number
!= n
) {
1003 current_font_number
= n
;
1005 int size
= tf
->get_size().to_scaled_points();
1006 if (current_size
!= size
) {
1010 current_size
= size
;
1012 int slant
= tf
->get_slant();
1013 if (current_slant
!= slant
) {
1017 current_slant
= slant
;
1019 int height
= tf
->get_height();
1020 if (current_height
!= height
) {
1022 put(height
== 0 ? current_size
: height
);
1024 current_height
= height
;
1029 void troff_output_file::draw(char code
, hvpair
*point
, int npoints
,
1034 int size
= fsize
.to_scaled_points();
1035 if (current_size
!= size
) {
1039 current_size
= size
;
1047 put(point
[0].h
.to_units());
1050 for (i
= 0; i
< npoints
; i
++) {
1052 put(point
[i
].h
.to_units());
1054 put(point
[i
].v
.to_units());
1056 for (i
= 0; i
< npoints
; i
++)
1057 output_hpos
+= point
[i
].h
.to_units();
1060 for (i
= 0; i
< npoints
; i
++)
1061 output_vpos
+= point
[i
].v
.to_units();
1067 void troff_output_file::really_begin_page(int pageno
, vunits pl
)
1070 if (page_length
> V0
) {
1072 put(page_length
.to_units());
1077 current_font_number
= -1;
1079 // current_height = 0;
1080 // current_slant = 0;
1086 for (int i
= 0; i
< nfont_positions
; i
++)
1087 font_position
[i
] = NULL_SYMBOL
;
1093 void troff_output_file::really_copy_file(hunits x
, vunits y
, const char *filename
)
1099 FILE *ifp
= fopen(filename
, "r");
1101 error("can't open `%1': %2", filename
, strerror(errno
));
1104 while ((c
= getc(ifp
)) != EOF
)
1111 current_font_number
= -1;
1112 for (int i
= 0; i
< nfont_positions
; i
++)
1113 font_position
[i
] = NULL_SYMBOL
;
1116 void troff_output_file::really_transparent_char(unsigned char c
)
1121 troff_output_file::~troff_output_file()
1124 if (page_length
> V0
) {
1127 put(page_length
.to_units());
1131 a_delete font_position
;
1134 troff_output_file::troff_output_file()
1135 : current_height(0), current_slant(0), tbuf_len(0), nfont_positions(10)
1137 font_position
= new symbol
[nfont_positions
];
1142 put(units_per_inch
);
1153 output_file
*the_output
= 0;
1155 output_file::output_file()
1159 output_file::~output_file()
1163 real_output_file::real_output_file()
1167 if ((fp
= popen(pipe_command
, "w")) != 0) {
1171 error("pipe open failed: %1", strerror(errno
));
1177 real_output_file::~real_output_file()
1181 // To avoid looping, set fp to 0 before calling fatal().
1182 if (ferror(fp
) || fflush(fp
) < 0) {
1184 fatal("error writing output file");
1187 int result
= pclose(fp
);
1190 fatal("pclose failed");
1191 if ((result
& 0x7f) != 0)
1192 error("output process `%1' got fatal signal %2",
1193 pipe_command
, result
& 0x7f);
1195 int exit_status
= (result
>> 8) & 0xff;
1196 if (exit_status
!= 0)
1197 error("output process `%1' exited with status %2",
1198 pipe_command
, exit_status
);
1201 else if (fclose(fp
) < 0) {
1203 fatal("error closing output file");
1207 void real_output_file::flush()
1210 fatal("error writing output file");
1213 int real_output_file::is_printing()
1218 void real_output_file::begin_page(int pageno
, vunits page_length
)
1220 printing
= in_output_page_list(pageno
);
1222 really_begin_page(pageno
, page_length
);
1225 void real_output_file::copy_file(hunits x
, vunits y
, const char *filename
)
1228 really_copy_file(x
, y
, filename
);
1231 void real_output_file::transparent_char(unsigned char c
)
1234 really_transparent_char(c
);
1237 void real_output_file::print_line(hunits x
, vunits y
, node
*n
,
1238 vunits before
, vunits after
)
1241 really_print_line(x
, y
, n
, before
, after
);
1242 delete_node_list(n
);
1245 void real_output_file::really_copy_file(hunits
, vunits
, const char *)
1251 /* ascii_output_file */
1253 void ascii_output_file::really_transparent_char(unsigned char c
)
1258 void ascii_output_file::really_print_line(hunits
, vunits
, node
*n
, vunits
, vunits
)
1261 n
->ascii_print(this);
1267 void ascii_output_file::really_begin_page(int /*pageno*/, vunits
/*page_length*/)
1269 fputs("<beginning of page>\n", fp
);
1272 ascii_output_file::ascii_output_file()
1276 /* suppress_output_file */
1278 suppress_output_file::suppress_output_file()
1282 void suppress_output_file::really_print_line(hunits
, vunits
, node
*, vunits
, vunits
)
1286 void suppress_output_file::really_begin_page(int, vunits
)
1290 void suppress_output_file::really_transparent_char(unsigned char)
1294 /* glyphs, ligatures, kerns, discretionary breaks */
1296 class glyph_node
: public node
{
1297 static glyph_node
*free_list
;
1303 glyph_node(charinfo
*, tfont
*, hunits
, node
* = 0);
1306 void *operator new(size_t);
1307 void operator delete(void *);
1308 glyph_node(charinfo
*, tfont
*, node
* = 0);
1311 node
*merge_glyph_node(glyph_node
*);
1312 node
*merge_self(node
*);
1314 node
*last_char_node();
1316 void vertical_extent(vunits
*, vunits
*);
1317 hunits
subscript_correction();
1318 hunits
italic_correction();
1319 hunits
left_italic_correction();
1321 hyphenation_type
get_hyphenation_type();
1323 void tprint(troff_output_file
*);
1324 void zero_width_tprint(troff_output_file
*);
1325 hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
1326 node
*add_self(node
*, hyphen_list
**);
1327 int ends_sentence();
1328 int overlaps_vertically();
1329 int overlaps_horizontally();
1330 void ascii_print(ascii_output_file
*);
1331 void asciify(macro
*);
1332 int character_type();
1337 glyph_node
*glyph_node::free_list
= 0;
1339 class ligature_node
: public glyph_node
{
1343 ligature_node(charinfo
*, tfont
*, hunits
, node
*gn1
, node
*gn2
, node
*x
= 0);
1346 void *operator new(size_t);
1347 void operator delete(void *);
1348 ligature_node(charinfo
*, tfont
*, node
*gn1
, node
*gn2
, node
*x
= 0);
1351 node
*add_self(node
*, hyphen_list
**);
1352 hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
1353 void ascii_print(ascii_output_file
*);
1354 void asciify(macro
*);
1359 class kern_pair_node
: public node
{
1364 kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
= 0);
1367 node
*merge_glyph_node(glyph_node
*);
1368 node
*add_self(node
*, hyphen_list
**);
1369 hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
1370 node
*add_discretionary_hyphen();
1372 node
*last_char_node();
1373 hunits
italic_correction();
1374 hunits
subscript_correction();
1375 void tprint(troff_output_file
*);
1376 hyphenation_type
get_hyphenation_type();
1377 int ends_sentence();
1378 void ascii_print(ascii_output_file
*);
1379 void asciify(macro
*);
1384 class dbreak_node
: public node
{
1389 dbreak_node(node
*n
, node
*p
, node
*x
= 0);
1392 node
*merge_glyph_node(glyph_node
*);
1393 node
*add_discretionary_hyphen();
1395 node
*last_char_node();
1396 hunits
italic_correction();
1397 hunits
subscript_correction();
1398 void tprint(troff_output_file
*);
1399 breakpoint
*get_breakpoints(hunits width
, int ns
, breakpoint
*rest
= 0,
1402 int ends_sentence();
1403 void split(int, node
**, node
**);
1404 hyphenation_type
get_hyphenation_type();
1405 void ascii_print(ascii_output_file
*);
1406 void asciify(macro
*);
1411 void *glyph_node::operator new(size_t n
)
1413 assert(n
== sizeof(glyph_node
));
1415 const int BLOCK
= 1024;
1416 free_list
= (glyph_node
*)new char[sizeof(glyph_node
)*BLOCK
];
1417 for (int i
= 0; i
< BLOCK
- 1; i
++)
1418 free_list
[i
].next
= free_list
+ i
+ 1;
1419 free_list
[BLOCK
-1].next
= 0;
1421 glyph_node
*p
= free_list
;
1422 free_list
= (glyph_node
*)(free_list
->next
);
1427 void *ligature_node::operator new(size_t n
)
1432 void glyph_node::operator delete(void *p
)
1435 ((glyph_node
*)p
)->next
= free_list
;
1436 free_list
= (glyph_node
*)p
;
1440 void ligature_node::operator delete(void *p
)
1445 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, node
*x
)
1446 : ci(c
), tf(t
), node(x
)
1449 wid
= tf
->get_width(ci
);
1454 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, hunits w
, node
*x
)
1455 : ci(c
), tf(t
), wid(w
), node(x
)
1460 node
*glyph_node::copy()
1463 return new glyph_node(ci
, tf
, wid
);
1465 return new glyph_node(ci
, tf
);
1469 node
*glyph_node::merge_self(node
*nd
)
1471 return nd
->merge_glyph_node(this);
1474 int glyph_node::character_type()
1476 return tf
->get_character_type(ci
);
1479 node
*glyph_node::add_self(node
*n
, hyphen_list
**p
)
1481 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
1484 if (n
== 0 || (nn
= n
->merge_glyph_node(this)) == 0) {
1489 nn
= nn
->add_discretionary_hyphen();
1490 hyphen_list
*pp
= *p
;
1496 int glyph_node::overlaps_horizontally()
1498 return ci
->overlaps_horizontally();
1501 int glyph_node::overlaps_vertically()
1503 return ci
->overlaps_vertically();
1506 units
glyph_node::size()
1508 return tf
->get_size().to_units();
1511 hyphen_list
*glyph_node::get_hyphen_list(hyphen_list
*tail
)
1513 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
1517 tfont
*node::get_tfont()
1522 tfont
*glyph_node::get_tfont()
1527 node
*node::merge_glyph_node(glyph_node
* /*gn*/)
1532 node
*glyph_node::merge_glyph_node(glyph_node
*gn
)
1536 if ((lig
= tf
->get_lig(ci
, gn
->ci
)) != 0) {
1539 return new ligature_node(lig
, tf
, this, gn
, next1
);
1542 if (tf
->get_kern(ci
, gn
->ci
, &kern
)) {
1545 return new kern_pair_node(kern
, this, gn
, next1
);
1554 hunits
glyph_node::width()
1559 return tf
->get_width(ci
);
1563 node
*glyph_node::last_char_node()
1568 void glyph_node::vertical_extent(vunits
*min
, vunits
*max
)
1570 *min
= -tf
->get_char_height(ci
);
1571 *max
= tf
->get_char_depth(ci
);
1574 hunits
glyph_node::skew()
1576 return tf
->get_char_skew(ci
);
1579 hunits
glyph_node::subscript_correction()
1581 return tf
->get_subscript_correction(ci
);
1584 hunits
glyph_node::italic_correction()
1586 return tf
->get_italic_correction(ci
);
1589 hunits
glyph_node::left_italic_correction()
1591 return tf
->get_left_italic_correction(ci
);
1594 hyphenation_type
glyph_node::get_hyphenation_type()
1596 return HYPHEN_MIDDLE
;
1599 int glyph_node::ends_sentence()
1601 if (ci
->ends_sentence())
1603 else if (ci
->transparent())
1609 void glyph_node::ascii_print(ascii_output_file
*ascii
)
1611 unsigned char c
= ci
->get_ascii_code();
1615 ascii
->outs(ci
->nm
.contents());
1618 ligature_node::ligature_node(charinfo
*c
, tfont
*t
,
1619 node
*gn1
, node
*gn2
, node
*x
)
1620 : glyph_node(c
, t
, x
), n1(gn1
), n2(gn2
)
1625 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, hunits w
,
1626 node
*gn1
, node
*gn2
, node
*x
)
1627 : glyph_node(c
, t
, w
, x
), n1(gn1
), n2(gn2
)
1632 ligature_node::~ligature_node()
1638 node
*ligature_node::copy()
1641 return new ligature_node(ci
, tf
, wid
, n1
->copy(), n2
->copy());
1643 return new ligature_node(ci
, tf
, n1
->copy(), n2
->copy());
1647 void ligature_node::ascii_print(ascii_output_file
*ascii
)
1649 n1
->ascii_print(ascii
);
1650 n2
->ascii_print(ascii
);
1653 hyphen_list
*ligature_node::get_hyphen_list(hyphen_list
*tail
)
1655 return n1
->get_hyphen_list(n2
->get_hyphen_list(tail
));
1658 node
*ligature_node::add_self(node
*n
, hyphen_list
**p
)
1660 n
= n1
->add_self(n
, p
);
1661 n
= n2
->add_self(n
, p
);
1667 kern_pair_node::kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
)
1668 : node(x
), n1(first
), n2(second
), amount(n
)
1672 dbreak_node::dbreak_node(node
*n
, node
*p
, node
*x
)
1673 : node(x
), none(n
), pre(p
), post(0)
1677 node
*dbreak_node::merge_glyph_node(glyph_node
*gn
)
1679 glyph_node
*gn2
= (glyph_node
*)gn
->copy();
1680 node
*new_none
= none
? none
->merge_glyph_node(gn
) : 0;
1681 node
*new_post
= post
? post
->merge_glyph_node(gn2
) : 0;
1682 if (new_none
== 0 && new_post
== 0) {
1701 node
*kern_pair_node::merge_glyph_node(glyph_node
*gn
)
1703 node
*nd
= n2
->merge_glyph_node(gn
);
1707 nd
= n2
->merge_self(n1
);
1719 hunits
kern_pair_node::italic_correction()
1721 return n2
->italic_correction();
1724 hunits
kern_pair_node::subscript_correction()
1726 return n2
->subscript_correction();
1729 node
*kern_pair_node::add_discretionary_hyphen()
1731 tfont
*tf
= n2
->get_tfont();
1733 if (tf
->contains(soft_hyphen_char
)) {
1737 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
);
1738 node
*nn
= n
->merge_glyph_node(gn
);
1743 return new dbreak_node(this, nn
, next1
);
1750 kern_pair_node::~kern_pair_node()
1758 dbreak_node::~dbreak_node()
1760 delete_node_list(pre
);
1761 delete_node_list(post
);
1762 delete_node_list(none
);
1765 node
*kern_pair_node::copy()
1767 return new kern_pair_node(amount
, n1
->copy(), n2
->copy());
1770 node
*copy_node_list(node
*n
)
1774 node
*nn
= n
->copy();
1788 void delete_node_list(node
*n
)
1797 node
*dbreak_node::copy()
1799 dbreak_node
*p
= new dbreak_node(copy_node_list(none
), copy_node_list(pre
));
1800 p
->post
= copy_node_list(post
);
1804 hyphen_list
*node::get_hyphen_list(hyphen_list
*tail
)
1810 hyphen_list
*kern_pair_node::get_hyphen_list(hyphen_list
*tail
)
1812 return n1
->get_hyphen_list(n2
->get_hyphen_list(tail
));
1815 class hyphen_inhibitor_node
: public node
{
1817 hyphen_inhibitor_node(node
*nd
= 0);
1821 hyphenation_type
get_hyphenation_type();
1824 hyphen_inhibitor_node::hyphen_inhibitor_node(node
*nd
) : node(nd
)
1828 node
*hyphen_inhibitor_node::copy()
1830 return new hyphen_inhibitor_node
;
1833 int hyphen_inhibitor_node::same(node
*)
1838 const char *hyphen_inhibitor_node::type()
1840 return "hyphen_inhibitor_node";
1843 hyphenation_type
hyphen_inhibitor_node::get_hyphenation_type()
1845 return HYPHEN_INHIBIT
;
1848 /* add_discretionary_hyphen methods */
1850 node
*dbreak_node::add_discretionary_hyphen()
1853 post
= post
->add_discretionary_hyphen();
1855 none
= none
->add_discretionary_hyphen();
1860 node
*node::add_discretionary_hyphen()
1862 tfont
*tf
= get_tfont();
1864 return new hyphen_inhibitor_node(this);
1865 if (tf
->contains(soft_hyphen_char
)) {
1869 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
);
1870 node
*n1
= n
->merge_glyph_node(gn
);
1875 return new dbreak_node(this, n1
, next1
);
1881 node
*node::merge_self(node
*)
1886 node
*node::add_self(node
*n
, hyphen_list
** /*p*/)
1892 node
*kern_pair_node::add_self(node
*n
, hyphen_list
**p
)
1894 n
= n1
->add_self(n
, p
);
1895 n
= n2
->add_self(n
, p
);
1902 hunits
node::width()
1907 node
*node::last_char_node()
1912 hunits
hmotion_node::width()
1919 return points_to_units(10);
1922 hunits
kern_pair_node::width()
1924 return n1
->width() + n2
->width() + amount
;
1927 node
*kern_pair_node::last_char_node()
1929 node
*nd
= n2
->last_char_node();
1932 return n1
->last_char_node();
1935 hunits
dbreak_node::width()
1938 for (node
*n
= none
; n
!= 0; n
= n
->next
)
1943 node
*dbreak_node::last_char_node()
1945 for (node
*n
= none
; n
; n
= n
->next
) {
1946 node
*last
= n
->last_char_node();
1953 hunits
dbreak_node::italic_correction()
1955 return none
? none
->italic_correction() : H0
;
1958 hunits
dbreak_node::subscript_correction()
1960 return none
? none
->subscript_correction() : H0
;
1963 class italic_corrected_node
: public node
{
1967 italic_corrected_node(node
*, hunits
, node
* = 0);
1968 ~italic_corrected_node();
1970 void ascii_print(ascii_output_file
*);
1971 void asciify(macro
*m
);
1973 node
*last_char_node();
1974 void vertical_extent(vunits
*, vunits
*);
1975 int ends_sentence();
1976 int overlaps_horizontally();
1977 int overlaps_vertically();
1979 hyphenation_type
get_hyphenation_type();
1981 hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
1982 int character_type();
1983 void tprint(troff_output_file
*);
1984 hunits
subscript_correction();
1986 node
*add_self(node
*, hyphen_list
**);
1990 node
*node::add_italic_correction(hunits
*width
)
1992 hunits ic
= italic_correction();
1999 return new italic_corrected_node(this, ic
, next1
);
2003 italic_corrected_node::italic_corrected_node(node
*nn
, hunits xx
, node
*p
)
2004 : n(nn
), x(xx
), node(p
)
2009 italic_corrected_node::~italic_corrected_node()
2014 node
*italic_corrected_node::copy()
2016 return new italic_corrected_node(n
->copy(), x
);
2019 hunits
italic_corrected_node::width()
2021 return n
->width() + x
;
2024 void italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
2026 n
->vertical_extent(min
, max
);
2029 void italic_corrected_node::tprint(troff_output_file
*out
)
2035 hunits
italic_corrected_node::skew()
2037 return n
->skew() - x
/2;
2040 hunits
italic_corrected_node::subscript_correction()
2042 return n
->subscript_correction() - x
;
2045 void italic_corrected_node::ascii_print(ascii_output_file
*out
)
2047 n
->ascii_print(out
);
2050 int italic_corrected_node::ends_sentence()
2052 return n
->ends_sentence();
2055 int italic_corrected_node::overlaps_horizontally()
2057 return n
->overlaps_horizontally();
2060 int italic_corrected_node::overlaps_vertically()
2062 return n
->overlaps_vertically();
2065 node
*italic_corrected_node::last_char_node()
2067 return n
->last_char_node();
2070 tfont
*italic_corrected_node::get_tfont()
2072 return n
->get_tfont();
2075 hyphenation_type
italic_corrected_node::get_hyphenation_type()
2077 return n
->get_hyphenation_type();
2080 node
*italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
2082 nd
= n
->add_self(nd
, p
);
2083 hunits not_interested
;
2084 nd
= nd
->add_italic_correction(¬_interested
);
2090 hyphen_list
*italic_corrected_node::get_hyphen_list(hyphen_list
*tail
)
2092 return n
->get_hyphen_list(tail
);
2095 int italic_corrected_node::character_type()
2097 return n
->character_type();
2100 class break_char_node
: public node
{
2104 break_char_node(node
*, int, node
* = 0);
2108 vunits
vertical_width();
2109 node
*last_char_node();
2110 int character_type();
2111 int ends_sentence();
2112 node
*add_self(node
*, hyphen_list
**);
2113 hyphen_list
*get_hyphen_list(hyphen_list
*s
= 0);
2114 void tprint(troff_output_file
*);
2115 void zero_width_tprint(troff_output_file
*);
2116 void ascii_print(ascii_output_file
*);
2117 void asciify(macro
*m
);
2118 hyphenation_type
get_hyphenation_type();
2119 int overlaps_vertically();
2120 int overlaps_horizontally();
2127 break_char_node::break_char_node(node
*n
, int c
, node
*x
)
2128 : node(x
), ch(n
), break_code(c
)
2132 break_char_node::~break_char_node()
2137 node
*break_char_node::copy()
2139 return new break_char_node(ch
->copy(), break_code
);
2142 hunits
break_char_node::width()
2147 vunits
break_char_node::vertical_width()
2149 return ch
->vertical_width();
2152 node
*break_char_node::last_char_node()
2154 return ch
->last_char_node();
2157 int break_char_node::character_type()
2159 return ch
->character_type();
2162 int break_char_node::ends_sentence()
2164 return ch
->ends_sentence();
2167 node
*break_char_node::add_self(node
*n
, hyphen_list
**p
)
2169 assert((*p
)->hyphenation_code
== 0);
2170 if ((*p
)->breakable
&& (break_code
& 1)) {
2171 n
= new space_node(H0
, n
);
2176 if ((*p
)->breakable
&& (break_code
& 2)) {
2177 n
= new space_node(H0
, n
);
2180 hyphen_list
*pp
= *p
;
2186 hyphen_list
*break_char_node::get_hyphen_list(hyphen_list
*tail
)
2188 return new hyphen_list(0, tail
);
2191 hyphenation_type
break_char_node::get_hyphenation_type()
2193 return HYPHEN_MIDDLE
;
2196 void break_char_node::ascii_print(ascii_output_file
*ascii
)
2198 ch
->ascii_print(ascii
);
2201 int break_char_node::overlaps_vertically()
2203 return ch
->overlaps_vertically();
2206 int break_char_node::overlaps_horizontally()
2208 return ch
->overlaps_horizontally();
2211 units
break_char_node::size()
2216 tfont
*break_char_node::get_tfont()
2218 return ch
->get_tfont();
2221 node
*extra_size_node::copy()
2223 return new extra_size_node(n
);
2226 node
*vertical_size_node::copy()
2228 return new vertical_size_node(n
);
2231 node
*hmotion_node::copy()
2233 return new hmotion_node(n
);
2236 node
*space_char_hmotion_node::copy()
2238 return new space_char_hmotion_node(n
);
2241 node
*vmotion_node::copy()
2243 return new vmotion_node(n
);
2246 node
*dummy_node::copy()
2248 return new dummy_node
;
2251 node
*transparent_dummy_node::copy()
2253 return new transparent_dummy_node
;
2256 hline_node::~hline_node()
2262 node
*hline_node::copy()
2264 return new hline_node(x
, n
? n
->copy() : 0);
2267 hunits
hline_node::width()
2269 return x
< H0
? H0
: x
;
2273 vline_node::~vline_node()
2279 node
*vline_node::copy()
2281 return new vline_node(x
, n
? n
->copy() : 0);
2284 hunits
vline_node::width()
2286 return n
== 0 ? H0
: n
->width();
2290 zero_width_node::zero_width_node(node
*nd
) : n(nd
)
2294 zero_width_node::~zero_width_node()
2296 delete_node_list(n
);
2299 node
*zero_width_node::copy()
2301 return new zero_width_node(copy_node_list(n
));
2304 int node_list_character_type(node
*p
)
2307 for (; p
; p
= p
->next
)
2308 t
|= p
->character_type();
2312 int zero_width_node::character_type()
2314 return node_list_character_type(n
);
2317 void node_list_vertical_extent(node
*p
, vunits
*min
, vunits
*max
)
2321 vunits cur_vpos
= V0
;
2323 for (; p
; p
= p
->next
) {
2324 p
->vertical_extent(&v1
, &v2
);
2331 cur_vpos
+= p
->vertical_width();
2335 void zero_width_node::vertical_extent(vunits
*min
, vunits
*max
)
2337 node_list_vertical_extent(n
, min
, max
);
2340 overstrike_node::overstrike_node() : max_width(H0
), list(0)
2344 overstrike_node::~overstrike_node()
2346 delete_node_list(list
);
2349 node
*overstrike_node::copy()
2351 overstrike_node
*on
= new overstrike_node
;
2352 for (node
*tem
= list
; tem
; tem
= tem
->next
)
2353 on
->overstrike(tem
->copy());
2357 void overstrike_node::overstrike(node
*n
)
2361 hunits w
= n
->width();
2364 for (node
**p
= &list
; *p
; p
= &(*p
)->next
)
2370 hunits
overstrike_node::width()
2375 bracket_node::bracket_node() : max_width(H0
), list(0)
2379 bracket_node::~bracket_node()
2381 delete_node_list(list
);
2384 node
*bracket_node::copy()
2386 bracket_node
*on
= new bracket_node
;
2387 for (node
*tem
= list
; tem
; tem
= tem
->next
)
2388 on
->bracket(tem
->copy());
2393 void bracket_node::bracket(node
*n
)
2397 hunits w
= n
->width();
2404 hunits
bracket_node::width()
2414 int node::merge_space(hunits
)
2420 space_node
*space_node::free_list
= 0;
2422 void *space_node::operator new(size_t n
)
2424 assert(n
== sizeof(space_node
));
2426 free_list
= (space_node
*)new char[sizeof(space_node
)*BLOCK
];
2427 for (int i
= 0; i
< BLOCK
- 1; i
++)
2428 free_list
[i
].next
= free_list
+ i
+ 1;
2429 free_list
[BLOCK
-1].next
= 0;
2431 space_node
*p
= free_list
;
2432 free_list
= (space_node
*)(free_list
->next
);
2437 inline void space_node::operator delete(void *p
)
2440 ((space_node
*)p
)->next
= free_list
;
2441 free_list
= (space_node
*)p
;
2446 space_node::space_node(hunits nn
, node
*p
) : node(p
), n(nn
), set(0)
2450 space_node::space_node(hunits nn
, int s
, node
*p
) : node(p
), n(nn
), set(s
)
2455 space_node::~space_node()
2460 node
*space_node::copy()
2462 return new space_node(n
, set
);
2465 int space_node::nspaces()
2470 int space_node::merge_space(hunits h
)
2476 hunits
space_node::width()
2481 void node::spread_space(int*, hunits
*)
2485 void space_node::spread_space(int *nspaces
, hunits
*desired_space
)
2488 assert(*nspaces
> 0);
2489 if (*nspaces
== 1) {
2490 n
+= *desired_space
;
2491 *desired_space
= H0
;
2494 hunits extra
= *desired_space
/ *nspaces
;
2495 *desired_space
-= extra
;
2503 void node::freeze_space()
2507 void space_node::freeze_space()
2512 diverted_space_node::diverted_space_node(vunits d
, node
*p
)
2517 node
*diverted_space_node::copy()
2519 return new diverted_space_node(n
);
2522 diverted_copy_file_node::diverted_copy_file_node(symbol s
, node
*p
)
2523 : node(p
), filename(s
)
2527 node
*diverted_copy_file_node::copy()
2529 return new diverted_copy_file_node(filename
);
2532 int node::ends_sentence()
2537 int kern_pair_node::ends_sentence()
2539 switch (n2
->ends_sentence()) {
2549 return n1
->ends_sentence();
2552 int node_list_ends_sentence(node
*n
)
2554 for (; n
!= 0; n
= n
->next
)
2555 switch (n
->ends_sentence()) {
2569 int dbreak_node::ends_sentence()
2571 return node_list_ends_sentence(none
);
2575 int node::overlaps_horizontally()
2580 int node::overlaps_vertically()
2585 int node::discardable()
2590 int space_node::discardable()
2596 vunits
node::vertical_width()
2601 vunits
vline_node::vertical_width()
2606 vunits
vmotion_node::vertical_width()
2611 int node::character_type()
2616 hunits
node::subscript_correction()
2621 hunits
node::italic_correction()
2626 hunits
node::left_italic_correction()
2637 /* vertical_extent methods */
2639 void node::vertical_extent(vunits
*min
, vunits
*max
)
2641 vunits v
= vertical_width();
2652 void vline_node::vertical_extent(vunits
*min
, vunits
*max
)
2655 node::vertical_extent(min
, max
);
2658 n
->vertical_extent(&cmin
, &cmax
);
2659 vunits h
= n
->size();
2666 // we print the first character and then move up, so
2668 // we print the last character and then move up h
2681 // we move down by h and then print the first character, so
2691 /* ascii_print methods */
2694 static void ascii_print_reverse_node_list(ascii_output_file
*ascii
, node
*n
)
2698 ascii_print_reverse_node_list(ascii
, n
->next
);
2699 n
->ascii_print(ascii
);
2702 void dbreak_node::ascii_print(ascii_output_file
*ascii
)
2704 ascii_print_reverse_node_list(ascii
, none
);
2707 void kern_pair_node::ascii_print(ascii_output_file
*ascii
)
2709 n1
->ascii_print(ascii
);
2710 n2
->ascii_print(ascii
);
2714 void node::ascii_print(ascii_output_file
*)
2718 void space_node::ascii_print(ascii_output_file
*ascii
)
2724 void hmotion_node::ascii_print(ascii_output_file
*ascii
)
2726 // this is pretty arbitrary
2727 if (n
>= points_to_units(2))
2731 void space_char_hmotion_node::ascii_print(ascii_output_file
*ascii
)
2736 /* asciify methods */
2738 void node::asciify(macro
*m
)
2743 void glyph_node::asciify(macro
*m
)
2745 unsigned char c
= ci
->get_ascii_code();
2754 void kern_pair_node::asciify(macro
*m
)
2762 static void asciify_reverse_node_list(macro
*m
, node
*n
)
2766 asciify_reverse_node_list(m
, n
->next
);
2770 void dbreak_node::asciify(macro
*m
)
2772 asciify_reverse_node_list(m
, none
);
2777 void ligature_node::asciify(macro
*m
)
2785 void break_char_node::asciify(macro
*m
)
2792 void italic_corrected_node::asciify(macro
*m
)
2799 void left_italic_corrected_node::asciify(macro
*m
)
2808 space_char_hmotion_node::space_char_hmotion_node(hunits i
, node
*next
)
2809 : hmotion_node(i
, next
)
2813 void space_char_hmotion_node::asciify(macro
*m
)
2819 void line_start_node::asciify(macro
*)
2824 void vertical_size_node::asciify(macro
*)
2829 breakpoint
*node::get_breakpoints(hunits
/*width*/, int /*nspaces*/,
2830 breakpoint
*rest
, int /*is_inner*/)
2840 breakpoint
*space_node::get_breakpoints(hunits width
, int ns
, breakpoint
*rest
,
2843 if (next
->discardable())
2845 breakpoint
*bp
= new breakpoint
;
2852 bp
->index
= rest
->index
+ 1;
2862 int space_node::nbreaks()
2864 if (next
->discardable())
2870 static breakpoint
*node_list_get_breakpoints(node
*p
, hunits
*widthp
,
2871 int ns
, breakpoint
*rest
)
2874 rest
= p
->get_breakpoints(*widthp
,
2876 node_list_get_breakpoints(p
->next
, widthp
, ns
,
2879 *widthp
+= p
->width();
2885 breakpoint
*dbreak_node::get_breakpoints(hunits width
, int ns
,
2886 breakpoint
*rest
, int is_inner
)
2888 breakpoint
*bp
= new breakpoint
;
2891 for (node
*tem
= pre
; tem
!= 0; tem
= tem
->next
)
2892 bp
->width
+= tem
->width();
2897 bp
->index
= rest
->index
+ 1;
2904 return node_list_get_breakpoints(none
, &width
, ns
, bp
);
2907 int dbreak_node::nbreaks()
2910 for (node
*tem
= none
; tem
!= 0; tem
= tem
->next
)
2911 i
+= tem
->nbreaks();
2915 void node::split(int /*where*/, node
** /*prep*/, node
** /*postp*/)
2920 void space_node::split(int where
, node
**pre
, node
**post
)
2928 static void node_list_split(node
*p
, int *wherep
, node
**prep
, node
**postp
)
2932 int nb
= p
->nbreaks();
2933 node_list_split(p
->next
, wherep
, prep
, postp
);
2938 else if (*wherep
< nb
) {
2940 p
->split(*wherep
, prep
, postp
);
2949 void dbreak_node::split(int where
, node
**prep
, node
**postp
)
2958 for (node
*tem
= pre
; tem
->next
!= 0; tem
= tem
->next
)
2969 node_list_split(none
, &where
, prep
, postp
);
2976 hyphenation_type
node::get_hyphenation_type()
2978 return HYPHEN_BOUNDARY
;
2982 hyphenation_type
dbreak_node::get_hyphenation_type()
2984 return HYPHEN_INHIBIT
;
2987 hyphenation_type
kern_pair_node::get_hyphenation_type()
2989 return HYPHEN_MIDDLE
;
2992 hyphenation_type
dummy_node::get_hyphenation_type()
2994 return HYPHEN_MIDDLE
;
2997 hyphenation_type
transparent_dummy_node::get_hyphenation_type()
2999 return HYPHEN_MIDDLE
;
3002 int node::interpret(macro
*)
3007 special_node::special_node(const macro
&m
)
3012 int special_node::same(node
*n
)
3014 return mac
== ((special_node
*)n
)->mac
;
3017 const char *special_node::type()
3019 return "special_node";
3022 node
*special_node::copy()
3024 return new special_node(mac
);
3027 void special_node::tprint_start(troff_output_file
*out
)
3029 out
->start_special();
3032 void special_node::tprint_char(troff_output_file
*out
, unsigned char c
)
3034 out
->special_char(c
);
3037 void special_node::tprint_end(troff_output_file
*out
)
3042 /* composite_node */
3044 class composite_node
: public node
{
3049 composite_node(node
*, charinfo
*, tfont
*, node
* = 0);
3053 node
*last_char_node();
3055 void tprint(troff_output_file
*);
3056 hyphenation_type
get_hyphenation_type();
3057 int overlaps_horizontally();
3058 int overlaps_vertically();
3059 void ascii_print(ascii_output_file
*);
3060 void asciify(macro
*);
3061 hyphen_list
*get_hyphen_list(hyphen_list
*tail
);
3062 node
*add_self(node
*, hyphen_list
**);
3066 void vertical_extent(vunits
*, vunits
*);
3067 vunits
vertical_width();
3070 composite_node::composite_node(node
*p
, charinfo
*c
, tfont
*t
, node
*x
)
3071 : node(x
), n(p
), ci(c
), tf(t
)
3075 composite_node::~composite_node()
3077 delete_node_list(n
);
3080 node
*composite_node::copy()
3082 return new composite_node(copy_node_list(n
), ci
, tf
);
3085 hunits
composite_node::width()
3088 if (tf
->get_constant_space(&x
))
3091 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3094 if (tf
->get_bold(&offset
))
3096 x
+= tf
->get_track_kern();
3100 node
*composite_node::last_char_node()
3105 vunits
composite_node::vertical_width()
3108 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3109 v
+= tem
->vertical_width();
3113 units
composite_node::size()
3115 return tf
->get_size().to_units();
3118 hyphenation_type
composite_node::get_hyphenation_type()
3120 return HYPHEN_MIDDLE
;
3123 int composite_node::overlaps_horizontally()
3125 return ci
->overlaps_horizontally();
3128 int composite_node::overlaps_vertically()
3130 return ci
->overlaps_vertically();
3133 void composite_node::asciify(macro
*m
)
3135 unsigned char c
= ci
->get_ascii_code();
3144 void composite_node::ascii_print(ascii_output_file
*ascii
)
3146 unsigned char c
= ci
->get_ascii_code();
3150 ascii
->outs(ci
->nm
.contents());
3154 hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
)
3156 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
3160 node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
3162 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
3166 nn
= nn
->add_discretionary_hyphen();
3167 hyphen_list
*pp
= *p
;
3173 tfont
*composite_node::get_tfont()
3178 node
*reverse_node_list(node
*n
)
3190 void composite_node::vertical_extent(vunits
*min
, vunits
*max
)
3192 n
= reverse_node_list(n
);
3193 node_list_vertical_extent(n
, min
, max
);
3194 n
= reverse_node_list(n
);
3197 word_space_node::word_space_node(hunits d
, node
*x
) : space_node(d
, x
)
3201 word_space_node::word_space_node(hunits d
, int s
, node
*x
)
3202 : space_node(d
, s
, x
)
3206 node
*word_space_node::copy()
3208 return new word_space_node(n
, set
);
3211 void word_space_node::tprint(troff_output_file
*out
)
3214 space_node::tprint(out
);
3217 unbreakable_space_node::unbreakable_space_node(hunits d
, node
*x
)
3218 : word_space_node(d
, x
)
3222 unbreakable_space_node::unbreakable_space_node(hunits d
, int s
, node
*x
)
3223 : word_space_node(d
, s
, x
)
3227 node
*unbreakable_space_node::copy()
3229 return new unbreakable_space_node(n
, set
);
3232 breakpoint
*unbreakable_space_node::get_breakpoints(hunits
, int,
3233 breakpoint
*rest
, int)
3238 int unbreakable_space_node::nbreaks()
3243 void unbreakable_space_node::split(int, node
**, node
**)
3248 int unbreakable_space_node::merge_space(hunits
)
3257 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
)
3258 : code(c
), npoints(np
), sz(s
)
3260 point
= new hvpair
[npoints
];
3261 for (int i
= 0; i
< npoints
; i
++)
3265 int draw_node::same(node
*n
)
3267 draw_node
*nd
= (draw_node
*)n
;
3268 if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
)
3270 for (int i
= 0; i
< npoints
; i
++)
3271 if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
3276 const char *draw_node::type()
3281 draw_node::~draw_node()
3287 hunits
draw_node::width()
3290 for (int i
= 0; i
< npoints
; i
++)
3295 vunits
draw_node::vertical_width()
3300 for (int i
= 0; i
< npoints
; i
++)
3305 node
*draw_node::copy()
3307 return new draw_node(code
, point
, npoints
, sz
);
3310 void draw_node::tprint(troff_output_file
*out
)
3312 out
->draw(code
, point
, npoints
, sz
);
3315 /* tprint methods */
3317 void glyph_node::tprint(troff_output_file
*out
)
3319 tfont
*ptf
= tf
->get_plain();
3321 out
->put_char_width(ci
, ptf
, width(), H0
);
3324 int bold
= tf
->get_bold(&offset
);
3325 hunits w
= ptf
->get_width(ci
);
3328 int cs
= tf
->get_constant_space(&x
);
3338 k
= tf
->get_track_kern();
3340 out
->put_char(ci
, ptf
);
3343 out
->put_char_width(ci
, ptf
, w
, k
);
3347 void glyph_node::zero_width_tprint(troff_output_file
*out
)
3349 tfont
*ptf
= tf
->get_plain();
3351 int bold
= tf
->get_bold(&offset
);
3353 int cs
= tf
->get_constant_space(&x
);
3355 x
-= ptf
->get_width(ci
);
3361 out
->put_char(ci
, ptf
);
3364 out
->put_char(ci
, ptf
);
3365 out
->right(-offset
);
3371 void break_char_node::tprint(troff_output_file
*t
)
3376 void break_char_node::zero_width_tprint(troff_output_file
*t
)
3378 ch
->zero_width_tprint(t
);
3381 void hline_node::tprint(troff_output_file
*out
)
3391 hunits w
= n
->width();
3393 error("horizontal line drawing character must have positive width");
3403 out
->right(xx
- xx2
);
3406 hunits rem
= x
- w
*i
;
3408 if (n
->overlaps_horizontally()) {
3410 out
->right(rem
- w
);
3419 void vline_node::tprint(troff_output_file
*out
)
3425 vunits h
= n
->size();
3426 int overlaps
= n
->overlaps_vertically();
3431 vunits rem
= y
- i
*h
;
3433 out
->right(n
->width());
3438 n
->zero_width_tprint(out
);
3442 n
->zero_width_tprint(out
);
3449 out
->down(-h
- rem
);
3455 vunits rem
= y
- i
*h
;
3458 out
->right(n
->width());
3463 n
->zero_width_tprint(out
);
3466 n
->zero_width_tprint(out
);
3474 void zero_width_node::tprint(troff_output_file
*out
)
3479 n
->zero_width_tprint(out
);
3482 int hpos
= out
->get_hpos();
3483 int vpos
= out
->get_vpos();
3489 out
->moveto(hpos
, vpos
);
3492 void overstrike_node::tprint(troff_output_file
*out
)
3495 for (node
*tem
= list
; tem
; tem
= tem
->next
) {
3496 hunits x
= (max_width
- tem
->width())/2;
3497 out
->right(x
- pos
);
3499 tem
->zero_width_tprint(out
);
3501 out
->right(max_width
- pos
);
3504 void bracket_node::tprint(troff_output_file
*out
)
3509 for (node
*tem
= list
; tem
; tem
= tem
->next
)
3511 vunits h
= list
->size();
3512 vunits totalh
= h
*npieces
;
3513 vunits y
= (totalh
- h
)/2;
3515 for (tem
= list
; tem
; tem
= tem
->next
) {
3516 tem
->zero_width_tprint(out
);
3519 out
->right(max_width
);
3520 out
->down(totalh
- y
);
3523 void node::tprint(troff_output_file
*)
3527 void node::zero_width_tprint(troff_output_file
*out
)
3529 int hpos
= out
->get_hpos();
3530 int vpos
= out
->get_vpos();
3532 out
->moveto(hpos
, vpos
);
3535 void space_node::tprint(troff_output_file
*out
)
3540 void hmotion_node::tprint(troff_output_file
*out
)
3545 void vmotion_node::tprint(troff_output_file
*out
)
3550 void kern_pair_node::tprint(troff_output_file
*out
)
3557 static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
3561 tprint_reverse_node_list(out
, n
->next
);
3565 void dbreak_node::tprint(troff_output_file
*out
)
3567 tprint_reverse_node_list(out
, none
);
3570 void composite_node::tprint(troff_output_file
*out
)
3573 int is_bold
= tf
->get_bold(&bold_offset
);
3574 hunits track_kern
= tf
->get_track_kern();
3575 hunits constant_space
;
3576 int is_constant_spaced
= tf
->get_constant_space(&constant_space
);
3578 if (is_constant_spaced
) {
3580 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3589 int hpos
= out
->get_hpos();
3590 int vpos
= out
->get_vpos();
3591 tprint_reverse_node_list(out
, n
);
3592 out
->moveto(hpos
, vpos
);
3593 out
->right(bold_offset
);
3595 tprint_reverse_node_list(out
, n
);
3596 if (is_constant_spaced
)
3599 out
->right(track_kern
);
3602 node
*make_composite_node(charinfo
*s
, environment
*env
)
3604 int fontno
= env_definite_font(env
);
3606 error("no current font");
3609 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
3610 node
*n
= charinfo_to_node_list(s
, env
);
3611 font_size fs
= env
->get_font_size();
3612 int char_height
= env
->get_char_height();
3613 int char_slant
= env
->get_char_slant();
3614 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
,
3616 if (env
->is_composite())
3617 tf
= tf
->get_plain();
3618 return new composite_node(n
, s
, tf
);
3621 node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
3623 int fontno
= env_definite_font(env
);
3625 error("no current font");
3628 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
3630 int found
= font_table
[fontno
]->contains(s
);
3632 if (s
->numbered()) {
3633 if (!no_error_message
)
3634 warning(WARN_CHAR
, "can't find numbered character %1",
3638 special_font_list
*sf
= font_table
[fontno
]->sf
;
3639 while (sf
!= 0 && !found
) {
3642 found
= font_table
[fn
]->contains(s
);
3646 sf
= global_special_fonts
;
3647 while (sf
!= 0 && !found
) {
3650 found
= font_table
[fn
]->contains(s
);
3656 && global_special_fonts
== 0 && font_table
[fontno
]->sf
== 0
3659 for (fn
= 0; fn
< font_table_size
; fn
++)
3661 && font_table
[fn
]->is_special()
3662 && font_table
[fn
]->contains(s
)) {
3668 if (!no_error_message
&& s
->first_time_not_found()) {
3669 unsigned char input_code
= s
->get_ascii_code();
3670 if (input_code
!= 0) {
3671 if (csgraph(input_code
))
3672 warning(WARN_CHAR
, "can't find character `%1'", input_code
);
3674 warning(WARN_CHAR
, "can't find character with input code %1",
3678 warning(WARN_CHAR
, "can't find special character `%1'",
3684 font_size fs
= env
->get_font_size();
3685 int char_height
= env
->get_char_height();
3686 int char_slant
= env
->get_char_slant();
3687 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
3688 if (env
->is_composite())
3689 tf
= tf
->get_plain();
3690 return new glyph_node(s
, tf
);
3693 node
*make_node(charinfo
*ci
, environment
*env
)
3695 switch (ci
->get_special_translation()) {
3696 case charinfo::TRANSLATE_SPACE
:
3697 return new space_char_hmotion_node(env
->get_space_width());
3698 case charinfo::TRANSLATE_DUMMY
:
3699 return new dummy_node
;
3700 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
3701 error("translation to \\% ignored in this context");
3704 charinfo
*tem
= ci
->get_translation();
3707 macro
*mac
= ci
->get_macro();
3709 return make_composite_node(ci
, env
);
3711 return make_glyph_node(ci
, env
);
3714 int character_exists(charinfo
*ci
, environment
*env
)
3716 if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
3718 charinfo
*tem
= ci
->get_translation();
3721 if (ci
->get_macro())
3723 node
*nd
= make_glyph_node(ci
, env
, 1);
3731 node
*node::add_char(charinfo
*ci
, environment
*env
, hunits
*widthp
)
3734 switch (ci
->get_special_translation()) {
3735 case charinfo::TRANSLATE_SPACE
:
3736 res
= new space_char_hmotion_node(env
->get_space_width(), this);
3737 *widthp
+= res
->width();
3739 case charinfo::TRANSLATE_DUMMY
:
3740 return new dummy_node(this);
3741 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
3742 return add_discretionary_hyphen();
3744 charinfo
*tem
= ci
->get_translation();
3747 macro
*mac
= ci
->get_macro();
3749 res
= make_composite_node(ci
, env
);
3752 *widthp
+= res
->width();
3758 node
*gn
= make_glyph_node(ci
, env
);
3762 hunits old_width
= width();
3763 node
*p
= gn
->merge_self(this);
3765 *widthp
+= gn
->width();
3770 *widthp
+= p
->width() - old_width
;
3776 if (ci
->can_break_before())
3778 if (ci
->can_break_after())
3781 node
*next1
= res
->next
;
3783 res
= new break_char_node(res
, break_code
, next1
);
3792 int same_node(node
*n1
, node
*n2
)
3796 return n1
->type() == n2
->type() && n1
->same(n2
);
3804 int same_node_list(node
*n1
, node
*n2
)
3807 if (n1
->type() != n2
->type() || !n1
->same(n2
))
3815 int extra_size_node::same(node
*nd
)
3817 return n
== ((extra_size_node
*)nd
)->n
;
3820 const char *extra_size_node::type()
3822 return "extra_size_node";
3825 int vertical_size_node::same(node
*nd
)
3827 return n
== ((vertical_size_node
*)nd
)->n
;
3830 const char *vertical_size_node::type()
3832 return "vertical_size_node";
3835 int hmotion_node::same(node
*nd
)
3837 return n
== ((hmotion_node
*)nd
)->n
;
3840 const char *hmotion_node::type()
3842 return "hmotion_node";
3845 int space_char_hmotion_node::same(node
*nd
)
3847 return n
== ((space_char_hmotion_node
*)nd
)->n
;
3850 const char *space_char_hmotion_node::type()
3852 return "space_char_hmotion_node";
3855 int vmotion_node::same(node
*nd
)
3857 return n
== ((vmotion_node
*)nd
)->n
;
3860 const char *vmotion_node::type()
3862 return "vmotion_node";
3865 int hline_node::same(node
*nd
)
3867 return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
3870 const char *hline_node::type()
3872 return "hline_node";
3875 int vline_node::same(node
*nd
)
3877 return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
3880 const char *vline_node::type()
3882 return "vline_node";
3885 int dummy_node::same(node
* /*nd*/)
3890 const char *dummy_node::type()
3892 return "dummy_node";
3895 int transparent_dummy_node::same(node
* /*nd*/)
3900 const char *transparent_dummy_node::type()
3902 return "transparent_dummy_node";
3905 int transparent_dummy_node::ends_sentence()
3910 int zero_width_node::same(node
*nd
)
3912 return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
3915 const char *zero_width_node::type()
3917 return "zero_width_node";
3920 int italic_corrected_node::same(node
*nd
)
3922 return (x
== ((italic_corrected_node
*)nd
)->x
3923 && same_node(n
, ((italic_corrected_node
*)nd
)->n
));
3926 const char *italic_corrected_node::type()
3928 return "italic_corrected_node";
3932 left_italic_corrected_node::left_italic_corrected_node(node
*x
)
3937 left_italic_corrected_node::~left_italic_corrected_node()
3942 node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
3945 hunits lic
= gn
->left_italic_correction();
3946 if (!lic
.is_zero()) {
3953 node
*nd
= n
->merge_glyph_node(gn
);
3956 x
= n
->left_italic_correction();
3963 node
*left_italic_corrected_node::copy()
3965 left_italic_corrected_node
*nd
= new left_italic_corrected_node
;
3973 void left_italic_corrected_node::tprint(troff_output_file
*out
)
3981 const char *left_italic_corrected_node::type()
3983 return "left_italic_corrected_node";
3986 int left_italic_corrected_node::same(node
*nd
)
3988 return (x
== ((left_italic_corrected_node
*)nd
)->x
3989 && same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
3992 void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
3995 n
->ascii_print(out
);
3998 hunits
left_italic_corrected_node::width()
4000 return n
? n
->width() + x
: H0
;
4003 void left_italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
4006 n
->vertical_extent(min
, max
);
4008 node::vertical_extent(min
, max
);
4011 hunits
left_italic_corrected_node::skew()
4013 return n
? n
->skew() + x
/2 : H0
;
4016 hunits
left_italic_corrected_node::subscript_correction()
4018 return n
? n
->subscript_correction() : H0
;
4021 hunits
left_italic_corrected_node::italic_correction()
4023 return n
? n
->italic_correction() : H0
;
4026 int left_italic_corrected_node::ends_sentence()
4028 return n
? n
->ends_sentence() : 0;
4031 int left_italic_corrected_node::overlaps_horizontally()
4033 return n
? n
->overlaps_horizontally() : 0;
4036 int left_italic_corrected_node::overlaps_vertically()
4038 return n
? n
->overlaps_vertically() : 0;
4041 node
*left_italic_corrected_node::last_char_node()
4043 return n
? n
->last_char_node() : 0;
4046 tfont
*left_italic_corrected_node::get_tfont()
4048 return n
? n
->get_tfont() : 0;
4051 hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
4054 return n
->get_hyphenation_type();
4056 return HYPHEN_MIDDLE
;
4059 hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
)
4061 return n
? n
->get_hyphen_list(tail
) : tail
;
4064 node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
4067 nd
= new left_italic_corrected_node(nd
);
4068 nd
= n
->add_self(nd
, p
);
4075 int left_italic_corrected_node::character_type()
4077 return n
? n
->character_type() : 0;
4080 int overstrike_node::same(node
*nd
)
4082 return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
4085 const char *overstrike_node::type()
4087 return "overstrike_node";
4090 int bracket_node::same(node
*nd
)
4092 return same_node_list(list
, ((bracket_node
*)nd
)->list
);
4095 const char *bracket_node::type()
4097 return "bracket_node";
4100 int composite_node::same(node
*nd
)
4102 return ci
== ((composite_node
*)nd
)->ci
4103 && same_node_list(n
, ((composite_node
*)nd
)->n
);
4106 const char *composite_node::type()
4108 return "composite_node";
4111 int glyph_node::same(node
*nd
)
4113 return ci
== ((glyph_node
*)nd
)->ci
&& tf
== ((glyph_node
*)nd
)->tf
;
4116 const char *glyph_node::type()
4118 return "glyph_node";
4121 int ligature_node::same(node
*nd
)
4123 return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
4124 && same_node(n2
, ((ligature_node
*)nd
)->n2
)
4125 && glyph_node::same(nd
));
4128 const char *ligature_node::type()
4130 return "ligature_node";
4133 int kern_pair_node::same(node
*nd
)
4135 return (amount
== ((kern_pair_node
*)nd
)->amount
4136 && same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
4137 && same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
4140 const char *kern_pair_node::type()
4142 return "kern_pair_node";
4145 int dbreak_node::same(node
*nd
)
4147 return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
4148 && same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
4149 && same_node_list(post
, ((dbreak_node
*)nd
)->post
));
4152 const char *dbreak_node::type()
4154 return "dbreak_node";
4157 int break_char_node::same(node
*nd
)
4159 return (break_code
== ((break_char_node
*)nd
)->break_code
4160 && same_node(ch
, ((break_char_node
*)nd
)->ch
));
4163 const char *break_char_node::type()
4165 return "break_char_node";
4168 int line_start_node::same(node
* /*nd*/)
4173 const char *line_start_node::type()
4175 return "line_start_node";
4178 int space_node::same(node
*nd
)
4180 return n
== ((space_node
*)nd
)->n
&& set
== ((space_node
*)nd
)->set
;
4183 const char *space_node::type()
4185 return "space_node";
4188 int word_space_node::same(node
*nd
)
4190 return (n
== ((word_space_node
*)nd
)->n
4191 && set
== ((word_space_node
*)nd
)->set
);
4194 const char *word_space_node::type()
4196 return "word_space_node";
4199 int unbreakable_space_node::same(node
*nd
)
4201 return (n
== ((unbreakable_space_node
*)nd
)->n
4202 && set
== ((unbreakable_space_node
*)nd
)->set
);
4205 const char *unbreakable_space_node::type()
4207 return "unbreakable_space_node";
4210 int diverted_space_node::same(node
*nd
)
4212 return n
== ((diverted_space_node
*)nd
)->n
;
4215 const char *diverted_space_node::type()
4217 return "diverted_space_node";
4220 int diverted_copy_file_node::same(node
*nd
)
4222 return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
4225 const char *diverted_copy_file_node::type()
4227 return "diverted_copy_file_node";
4230 // Grow the font_table so that its size is > n.
4232 static void grow_font_table(int n
)
4234 assert(n
>= font_table_size
);
4235 font_info
**old_font_table
= font_table
;
4236 int old_font_table_size
= font_table_size
;
4237 font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
4238 if (font_table_size
<= n
)
4239 font_table_size
= n
+ 10;
4240 font_table
= new font_info
*[font_table_size
];
4241 if (old_font_table_size
)
4242 memcpy(font_table
, old_font_table
,
4243 old_font_table_size
*sizeof(font_info
*));
4244 a_delete old_font_table
;
4245 for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
4249 dictionary
font_translation_dictionary(17);
4251 static symbol
get_font_translation(symbol nm
)
4253 void *p
= font_translation_dictionary
.lookup(nm
);
4254 return p
? symbol((char *)p
) : nm
;
4257 dictionary
font_dictionary(50);
4259 static int mount_font_no_translate(int n
, symbol name
, symbol external_name
)
4262 // We store the address of this char in font_dictionary to indicate
4263 // that we've previously tried to mount the font and failed.
4266 void *p
= font_dictionary
.lookup(external_name
);
4269 fm
= font::load_font(external_name
.contents(), ¬_found
);
4272 warning(WARN_FONT
, "can't find font `%1'", external_name
.contents());
4273 font_dictionary
.lookup(external_name
, &a_char
);
4276 font_dictionary
.lookup(name
, fm
);
4278 else if (p
== &a_char
) {
4280 error("invalid font `%1'", external_name
.contents());
4286 if (n
>= font_table_size
) {
4287 if (n
- font_table_size
> 1000) {
4288 error("font position too much larger than first unused position");
4293 else if (font_table
[n
] != 0)
4294 delete font_table
[n
];
4295 font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
4296 invalidate_fontno(n
);
4300 int mount_font(int n
, symbol name
, symbol external_name
)
4303 name
= get_font_translation(name
);
4304 if (external_name
.is_null())
4305 external_name
= name
;
4307 external_name
= get_font_translation(external_name
);
4308 return mount_font_no_translate(n
, name
, external_name
);
4311 void mount_style(int n
, symbol name
)
4314 if (n
>= font_table_size
) {
4315 if (n
- font_table_size
> 1000) {
4316 error("font position too much larger than first unused position");
4321 else if (font_table
[n
] != 0)
4322 delete font_table
[n
];
4323 font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
4324 invalidate_fontno(n
);
4327 /* global functions */
4329 void font_translate()
4331 symbol from
= get_name(1);
4332 if (!from
.is_null()) {
4333 symbol to
= get_name();
4334 if (to
.is_null() || from
== to
)
4335 font_translation_dictionary
.remove(from
);
4337 font_translation_dictionary
.lookup(from
, (void *)to
.contents());
4342 void font_position()
4345 if (get_integer(&n
)) {
4347 error("negative font position");
4349 symbol internal_name
= get_name(1);
4350 if (!internal_name
.is_null()) {
4351 symbol external_name
= get_long_name(0);
4352 mount_font(n
, internal_name
, external_name
); // ignore error
4359 font_family::font_family(symbol s
)
4360 : nm(s
), map_size(10)
4362 map
= new int[map_size
];
4363 for (int i
= 0; i
< map_size
; i
++)
4367 font_family::~font_family()
4372 int font_family::make_definite(int i
)
4375 if (i
< map_size
&& map
[i
] >= 0)
4378 if (i
< font_table_size
&& font_table
[i
] != 0) {
4379 if (i
>= map_size
) {
4380 int old_map_size
= map_size
;
4386 map
= new int[map_size
];
4387 memcpy(map
, old_map
, old_map_size
*sizeof(int));
4389 for (int j
= old_map_size
; j
< map_size
; j
++)
4392 if (font_table
[i
]->is_style()) {
4393 symbol sty
= font_table
[i
]->get_name();
4394 symbol f
= concat(nm
, sty
);
4396 // don't use symbol_fontno, because that might return a style
4397 // and because we don't want to translate the name
4398 for (n
= 0; n
< font_table_size
; n
++)
4399 if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
4400 && !font_table
[n
]->is_style())
4402 if (n
>= font_table_size
) {
4403 n
= next_available_font_position();
4404 if (!mount_font_no_translate(n
, f
, f
))
4420 dictionary
family_dictionary(5);
4422 font_family
*lookup_family(symbol nm
)
4424 font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
4426 f
= new font_family(nm
);
4427 (void)family_dictionary
.lookup(nm
, f
);
4432 static void invalidate_fontno(int n
)
4434 assert(n
>= 0 && n
< font_table_size
);
4435 dictionary_iterator
iter(family_dictionary
);
4438 while (iter
.get(&nm
, (void **)&fam
)) {
4439 int map_size
= fam
->map_size
;
4442 for (int i
= 0; i
< map_size
; i
++)
4443 if (fam
->map
[i
] == n
)
4451 if (get_integer(&n
)) {
4453 error("negative font position");
4455 symbol internal_name
= get_name(1);
4456 if (!internal_name
.is_null())
4457 mount_style(n
, internal_name
);
4463 static int get_fontno()
4467 if (tok
.delimiter()) {
4468 symbol s
= get_name(1);
4470 n
= symbol_fontno(s
);
4472 n
= next_available_font_position();
4473 if (!mount_font(n
, s
))
4476 return curenv
->get_family()->make_definite(n
);
4479 else if (get_integer(&n
)) {
4480 if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
4481 error("bad font number");
4483 return curenv
->get_family()->make_definite(n
);
4488 static int underline_fontno
= 2;
4490 void underline_font()
4492 int n
= get_fontno();
4494 underline_fontno
= n
;
4498 int get_underline_fontno()
4500 return underline_fontno
;
4503 static void read_special_fonts(special_font_list
**sp
)
4505 special_font_list
*s
= *sp
;
4508 special_font_list
*tem
= s
;
4512 special_font_list
**p
= sp
;
4514 int i
= get_fontno();
4516 special_font_list
*tem
= new special_font_list
;
4525 void font_special_request()
4527 int n
= get_fontno();
4529 read_special_fonts(&font_table
[n
]->sf
);
4534 void special_request()
4536 read_special_fonts(&global_special_fonts
);
4540 int next_available_font_position()
4542 for (int i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
4547 int symbol_fontno(symbol s
)
4549 s
= get_font_translation(s
);
4550 for (int i
= 0; i
< font_table_size
; i
++)
4551 if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
4556 int is_good_fontno(int n
)
4558 return n
>= 0 && n
< font_table_size
&& font_table
[n
] != NULL
;
4561 int get_bold_fontno(int n
)
4563 if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
4565 if (font_table
[n
]->get_bold(&offset
))
4566 return offset
.to_units() + 1;
4574 hunits
env_digit_width(environment
*env
)
4576 node
*n
= make_glyph_node(charset_table
['0'], env
);
4578 hunits x
= n
->width();
4586 hunits
env_space_width(environment
*env
)
4588 int fn
= env_definite_font(env
);
4589 font_size fs
= env
->get_font_size();
4590 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
4591 return scale(fs
.to_units()/3, env
->get_space_size(), 12);
4593 return font_table
[fn
]->get_space_width(fs
, env
->get_space_size());
4596 hunits
env_sentence_space_width(environment
*env
)
4598 int fn
= env_definite_font(env
);
4599 font_size fs
= env
->get_font_size();
4600 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
4601 return scale(fs
.to_units()/3, env
->get_sentence_space_size(), 12);
4603 return font_table
[fn
]->get_space_width(fs
, env
->get_sentence_space_size());
4606 hunits
env_half_narrow_space_width(environment
*env
)
4608 int fn
= env_definite_font(env
);
4609 font_size fs
= env
->get_font_size();
4610 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
4613 return font_table
[fn
]->get_half_narrow_space_width(fs
);
4616 hunits
env_narrow_space_width(environment
*env
)
4618 int fn
= env_definite_font(env
);
4619 font_size fs
= env
->get_font_size();
4620 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
4623 return font_table
[fn
]->get_narrow_space_width(fs
);
4628 int n
= get_fontno();
4631 if (tok
.delimiter()) {
4632 int f
= get_fontno();
4635 if (has_arg() && get_number(&offset
, 'u') && offset
>= 1)
4636 font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
4638 font_table
[f
]->conditional_unbold(n
);
4643 if (get_number(&offset
, 'u') && offset
>= 1)
4644 font_table
[n
]->set_bold(hunits(offset
- 1));
4646 font_table
[n
]->unbold();
4650 font_table
[n
]->unbold();
4655 track_kerning_function::track_kerning_function() : non_zero(0)
4659 track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
4660 int max_s
, hunits max_a
)
4662 min_size(min_s
), min_amount(min_a
),
4663 max_size(max_s
), max_amount(max_a
)
4667 int track_kerning_function::operator==(const track_kerning_function
&tk
)
4671 && min_size
== tk
.min_size
4672 && min_amount
== tk
.min_amount
4673 && max_size
== tk
.max_size
4674 && max_amount
== tk
.max_amount
);
4676 return !tk
.non_zero
;
4679 int track_kerning_function::operator!=(const track_kerning_function
&tk
)
4682 return (!tk
.non_zero
4683 || min_size
!= tk
.min_size
4684 || min_amount
!= tk
.min_amount
4685 || max_size
!= tk
.max_size
4686 || max_amount
!= tk
.max_amount
);
4691 hunits
track_kerning_function::compute(int size
)
4694 if (max_size
<= min_size
)
4696 else if (size
<= min_size
)
4698 else if (size
>= max_size
)
4701 return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
4702 + scale(min_amount
, max_size
- size
, max_size
- min_size
));
4710 int n
= get_fontno();
4713 hunits min_a
, max_a
;
4715 && get_number(&min_s
, 'z')
4716 && get_hunits(&min_a
, 'p')
4717 && get_number(&max_s
, 'z')
4718 && get_hunits(&max_a
, 'p')) {
4719 track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
4720 font_table
[n
]->set_track_kern(tk
);
4723 track_kerning_function tk
;
4724 font_table
[n
]->set_track_kern(tk
);
4730 void constant_space()
4732 int n
= get_fontno();
4735 if (!has_arg() || !get_integer(&x
))
4736 font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
4738 if (!has_arg() || !get_number(&y
, 'z'))
4739 font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
4741 font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
4753 if (has_arg() && get_integer(&lig
) && lig
>= 0 && lig
<= 2)
4754 global_ligature_mode
= lig
;
4756 global_ligature_mode
= 1;
4763 if (has_arg() && get_integer(&k
))
4764 global_kern_mode
= k
!= 0;
4766 global_kern_mode
= 1;
4770 void set_soft_hyphen_char()
4772 soft_hyphen_char
= get_optional_char();
4773 if (!soft_hyphen_char
)
4774 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);
4780 if (suppress_output_flag
)
4781 the_output
= new suppress_output_file
;
4782 else if (ascii_output_flag
)
4783 the_output
= new ascii_output_file
;
4785 the_output
= new troff_output_file
;
4788 class next_available_font_position_reg
: public reg
{
4790 const char *get_string();
4793 const char *next_available_font_position_reg::get_string()
4795 return itoa(next_available_font_position());
4798 class printing_reg
: public reg
{
4800 const char *get_string();
4803 const char *printing_reg::get_string()
4806 return the_output
->is_printing() ? "1" : "0";
4811 void init_node_requests()
4813 init_request("fp", font_position
);
4814 init_request("sty", style
);
4815 init_request("cs", constant_space
);
4816 init_request("bd", bold_font
);
4817 init_request("uf", underline_font
);
4818 init_request("lg", ligature
);
4819 init_request("kern", kern_request
);
4820 init_request("tkf", track_kern
);
4821 init_request("special", special_request
);
4822 init_request("fspecial", font_special_request
);
4823 init_request("ftr", font_translate
);
4824 init_request("shc", set_soft_hyphen_char
);
4825 number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
4826 number_reg_dictionary
.define(".kern",
4827 new constant_int_reg(&global_kern_mode
));
4828 number_reg_dictionary
.define(".lg",
4829 new constant_int_reg(&global_ligature_mode
));
4830 number_reg_dictionary
.define(".P", new printing_reg
);
4831 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);