2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003
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. */
29 #include "dictionary.h"
41 #include "stringclass.h"
49 #else /* not _POSIX_VERSION */
51 /* traditional Unix */
53 #define WIFEXITED(s) (((s) & 0377) == 0)
54 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
55 #define WTERMSIG(s) ((s) & 0177)
56 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
57 #define WSTOPSIG(s) (((s) >> 8) & 0377)
58 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
60 #endif /* not _POSIX_VERSION */
63 * how many boundaries of images have been written? Useful for
68 static int suppress_start_page
= 0;
72 symbol
HYPHEN_SYMBOL("hy");
74 // Character used when a hyphen is inserted at a line break.
75 static charinfo
*soft_hyphen_char
;
77 enum constant_space_type
{
79 CONSTANT_SPACE_RELATIVE
,
80 CONSTANT_SPACE_ABSOLUTE
83 struct special_font_list
{
85 special_font_list
*next
;
88 special_font_list
*global_special_fonts
;
89 static int global_ligature_mode
= 1;
90 static int global_kern_mode
= 1;
92 class track_kerning_function
{
99 track_kerning_function();
100 track_kerning_function(units
, hunits
, units
, hunits
);
101 int operator==(const track_kerning_function
&);
102 int operator!=(const track_kerning_function
&);
103 hunits
compute(int point_size
);
106 // embolden fontno when this is the current font
108 struct conditional_bold
{
109 conditional_bold
*next
;
112 conditional_bold(int, hunits
, conditional_bold
* = 0);
123 symbol internal_name
;
124 symbol external_name
;
128 track_kerning_function track_kern
;
129 constant_space_type is_constant_spaced
;
130 units constant_space
;
131 int last_ligature_mode
;
133 conditional_bold
*cond_bold_list
;
136 special_font_list
*sf
;
137 font_info(symbol nm
, int n
, symbol enm
, font
*f
);
138 int contains(charinfo
*);
139 void set_bold(hunits
);
141 void set_conditional_bold(int, hunits
);
142 void conditional_unbold(int);
143 void set_track_kern(track_kerning_function
&);
144 void set_constant_space(constant_space_type
, units
= 0);
145 int is_named(symbol
);
147 tfont
*get_tfont(font_size
, int, int, int);
148 hunits
get_space_width(font_size
, int);
149 hunits
get_narrow_space_width(font_size
);
150 hunits
get_half_narrow_space_width(font_size
);
151 int get_bold(hunits
*);
154 friend symbol
get_font_name(int, environment
*);
164 char is_constant_spaced
;
168 hunits track_kern
; // add this to the width
169 hunits constant_space_width
;
173 tfont_spec(symbol nm
, int pos
, font
*, font_size
, int, int);
174 tfont_spec(const tfont_spec
&spec
) { *this = spec
; }
176 int operator==(const tfont_spec
&);
177 friend tfont
*font_info::get_tfont(font_size fs
, int, int, int);
180 class tfont
: public tfont_spec
{
181 static tfont
*tfont_list
;
183 tfont
*plain_version
;
186 int contains(charinfo
*);
187 hunits
get_width(charinfo
*c
);
188 int get_bold(hunits
*);
189 int get_constant_space(hunits
*);
190 hunits
get_track_kern();
192 font_size
get_size();
194 charinfo
*get_lig(charinfo
*c1
, charinfo
*c2
);
195 int get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
);
196 int get_input_position();
197 int get_character_type(charinfo
*);
200 vunits
get_char_height(charinfo
*);
201 vunits
get_char_depth(charinfo
*);
202 hunits
get_char_skew(charinfo
*);
203 hunits
get_italic_correction(charinfo
*);
204 hunits
get_left_italic_correction(charinfo
*);
205 hunits
get_subscript_correction(charinfo
*);
206 friend tfont
*make_tfont(tfont_spec
&);
209 inline int env_definite_font(environment
*env
)
211 return env
->get_family()->make_definite(env
->get_font());
214 /* font_info functions */
216 static font_info
**font_table
= 0;
217 static int font_table_size
= 0;
219 font_info::font_info(symbol nm
, int n
, symbol enm
, font
*f
)
220 : last_tfont(0), number(n
), last_size(0),
221 internal_name(nm
), external_name(enm
), fm(f
),
222 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE
), last_ligature_mode(1),
223 last_kern_mode(1), cond_bold_list(0), sf(0)
227 inline int font_info::contains(charinfo
*ci
)
229 return fm
!= 0 && fm
->contains(ci
->get_index());
232 inline int font_info::is_special()
234 return fm
!= 0 && fm
->is_special();
237 inline int font_info::is_style()
242 tfont
*make_tfont(tfont_spec
&spec
)
244 for (tfont
*p
= tfont::tfont_list
; p
; p
= p
->next
)
247 return new tfont(spec
);
250 // this is the current_font, fontno is where we found the character,
251 // presumably a special font
253 tfont
*font_info::get_tfont(font_size fs
, int height
, int slant
, int fontno
)
255 if (last_tfont
== 0 || fs
!= last_size
256 || height
!= last_height
|| slant
!= last_slant
257 || global_ligature_mode
!= last_ligature_mode
258 || global_kern_mode
!= last_kern_mode
259 || fontno
!= number
) {
260 font_info
*f
= font_table
[fontno
];
261 tfont_spec
spec(f
->external_name
, f
->number
, f
->fm
, fs
, height
, slant
);
262 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
263 if (p
->fontno
== fontno
) {
265 spec
.bold_offset
= p
->offset
;
268 if (!spec
.is_bold
&& is_bold
) {
270 spec
.bold_offset
= bold_offset
;
272 spec
.track_kern
= track_kern
.compute(fs
.to_scaled_points());
273 spec
.ligature_mode
= global_ligature_mode
;
274 spec
.kern_mode
= global_kern_mode
;
275 switch (is_constant_spaced
) {
276 case CONSTANT_SPACE_NONE
:
278 case CONSTANT_SPACE_ABSOLUTE
:
279 spec
.is_constant_spaced
= 1;
280 spec
.constant_space_width
= constant_space
;
282 case CONSTANT_SPACE_RELATIVE
:
283 spec
.is_constant_spaced
= 1;
284 spec
.constant_space_width
285 = scale(constant_space
*fs
.to_scaled_points(),
292 if (fontno
!= number
)
293 return make_tfont(spec
);
294 last_tfont
= make_tfont(spec
);
296 last_height
= height
;
298 last_ligature_mode
= global_ligature_mode
;
299 last_kern_mode
= global_kern_mode
;
304 int font_info::get_bold(hunits
*res
)
314 void font_info::unbold()
322 void font_info::set_bold(hunits offset
)
324 if (!is_bold
|| offset
!= bold_offset
) {
326 bold_offset
= offset
;
331 void font_info::set_conditional_bold(int fontno
, hunits offset
)
333 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
334 if (p
->fontno
== fontno
) {
335 if (offset
!= p
->offset
) {
341 cond_bold_list
= new conditional_bold(fontno
, offset
, cond_bold_list
);
344 conditional_bold::conditional_bold(int f
, hunits h
, conditional_bold
*x
)
345 : next(x
), fontno(f
), offset(h
)
349 void font_info::conditional_unbold(int fontno
)
351 for (conditional_bold
**p
= &cond_bold_list
; *p
; p
= &(*p
)->next
)
352 if ((*p
)->fontno
== fontno
) {
353 conditional_bold
*tem
= *p
;
361 void font_info::set_constant_space(constant_space_type type
, units x
)
363 if (type
!= is_constant_spaced
364 || (type
!= CONSTANT_SPACE_NONE
&& x
!= constant_space
)) {
366 is_constant_spaced
= type
;
371 void font_info::set_track_kern(track_kerning_function
&tk
)
373 if (track_kern
!= tk
) {
379 void font_info::flush()
384 int font_info::is_named(symbol s
)
386 return internal_name
== s
;
389 symbol
font_info::get_name()
391 return internal_name
;
394 symbol
get_font_name(int fontno
, environment
*env
)
396 symbol f
= font_table
[fontno
]->get_name();
397 if (font_table
[fontno
]->is_style()) {
398 return concat(env
->get_family()->nm
, f
);
403 hunits
font_info::get_space_width(font_size fs
, int space_size
)
405 if (is_constant_spaced
== CONSTANT_SPACE_NONE
)
406 return scale(hunits(fm
->get_space_width(fs
.to_scaled_points())),
408 else if (is_constant_spaced
== CONSTANT_SPACE_ABSOLUTE
)
409 return constant_space
;
411 return scale(constant_space
*fs
.to_scaled_points(),
412 units_per_inch
, 36*72*sizescale
);
415 hunits
font_info::get_narrow_space_width(font_size fs
)
417 charinfo
*ci
= get_charinfo(symbol("|"));
418 if (fm
->contains(ci
->get_index()))
419 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
421 return hunits(fs
.to_units()/6);
424 hunits
font_info::get_half_narrow_space_width(font_size fs
)
426 charinfo
*ci
= get_charinfo(symbol("^"));
427 if (fm
->contains(ci
->get_index()))
428 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
430 return hunits(fs
.to_units()/12);
435 tfont_spec::tfont_spec(symbol nm
, int n
, font
*f
,
436 font_size s
, int h
, int sl
)
437 : name(nm
), input_position(n
), fm(f
), size(s
),
438 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
441 if (height
== size
.to_scaled_points())
445 int tfont_spec::operator==(const tfont_spec
&spec
)
449 && input_position
== spec
.input_position
451 && height
== spec
.height
452 && slant
== spec
.slant
454 ? (spec
.is_bold
&& bold_offset
== spec
.bold_offset
)
456 && track_kern
== spec
.track_kern
457 && (is_constant_spaced
458 ? (spec
.is_constant_spaced
459 && constant_space_width
== spec
.constant_space_width
)
460 : !spec
.is_constant_spaced
)
461 && ligature_mode
== spec
.ligature_mode
462 && kern_mode
== spec
.kern_mode
)
468 tfont_spec
tfont_spec::plain()
470 return tfont_spec(name
, input_position
, fm
, size
, height
, slant
);
473 hunits
tfont::get_width(charinfo
*c
)
475 if (is_constant_spaced
)
476 return constant_space_width
;
478 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
479 + track_kern
+ bold_offset
);
481 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
485 vunits
tfont::get_char_height(charinfo
*c
)
487 vunits v
= fm
->get_height(c
->get_index(), size
.to_scaled_points());
488 if (height
!= 0 && height
!= size
.to_scaled_points())
489 return scale(v
, height
, size
.to_scaled_points());
494 vunits
tfont::get_char_depth(charinfo
*c
)
496 vunits v
= fm
->get_depth(c
->get_index(), size
.to_scaled_points());
497 if (height
!= 0 && height
!= size
.to_scaled_points())
498 return scale(v
, height
, size
.to_scaled_points());
503 hunits
tfont::get_char_skew(charinfo
*c
)
505 return hunits(fm
->get_skew(c
->get_index(), size
.to_scaled_points(), slant
));
508 hunits
tfont::get_italic_correction(charinfo
*c
)
510 return hunits(fm
->get_italic_correction(c
->get_index(), size
.to_scaled_points()));
513 hunits
tfont::get_left_italic_correction(charinfo
*c
)
515 return hunits(fm
->get_left_italic_correction(c
->get_index(),
516 size
.to_scaled_points()));
519 hunits
tfont::get_subscript_correction(charinfo
*c
)
521 return hunits(fm
->get_subscript_correction(c
->get_index(),
522 size
.to_scaled_points()));
525 inline int tfont::get_input_position()
527 return input_position
;
530 inline int tfont::contains(charinfo
*ci
)
532 return fm
->contains(ci
->get_index());
535 inline int tfont::get_character_type(charinfo
*ci
)
537 return fm
->get_character_type(ci
->get_index());
540 inline int tfont::get_bold(hunits
*res
)
550 inline int tfont::get_constant_space(hunits
*res
)
552 if (is_constant_spaced
) {
553 *res
= constant_space_width
;
560 inline hunits
tfont::get_track_kern()
565 inline tfont
*tfont::get_plain()
567 return plain_version
;
570 inline font_size
tfont::get_size()
575 inline symbol
tfont::get_name()
580 inline int tfont::get_height()
585 inline int tfont::get_slant()
590 symbol
SYMBOL_ff("ff");
591 symbol
SYMBOL_fi("fi");
592 symbol
SYMBOL_fl("fl");
593 symbol
SYMBOL_Fi("Fi");
594 symbol
SYMBOL_Fl("Fl");
596 charinfo
*tfont::get_lig(charinfo
*c1
, charinfo
*c2
)
598 if (ligature_mode
== 0)
601 if (c1
->get_ascii_code() == 'f') {
602 switch (c2
->get_ascii_code()) {
604 if (fm
->has_ligature(font::LIG_ff
))
605 ci
= get_charinfo(SYMBOL_ff
);
608 if (fm
->has_ligature(font::LIG_fi
))
609 ci
= get_charinfo(SYMBOL_fi
);
612 if (fm
->has_ligature(font::LIG_fl
))
613 ci
= get_charinfo(SYMBOL_fl
);
617 else if (ligature_mode
!= 2 && c1
->nm
== SYMBOL_ff
) {
618 switch (c2
->get_ascii_code()) {
620 if (fm
->has_ligature(font::LIG_ffi
))
621 ci
= get_charinfo(SYMBOL_Fi
);
624 if (fm
->has_ligature(font::LIG_ffl
))
625 ci
= get_charinfo(SYMBOL_Fl
);
629 if (ci
!= 0 && fm
->contains(ci
->get_index()))
634 inline int tfont::get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
)
639 int n
= fm
->get_kern(c1
->get_index(),
641 size
.to_scaled_points());
651 tfont
*tfont::tfont_list
= 0;
653 tfont::tfont(tfont_spec
&spec
) : tfont_spec(spec
)
657 tfont_spec plain_spec
= plain();
659 for (p
= tfont_list
; p
; p
= p
->next
)
660 if (*p
== plain_spec
) {
665 plain_version
= new tfont(plain_spec
);
670 class real_output_file
: public output_file
{
671 #ifndef POPEN_MISSING
674 int printing
; // decision via optional page list
675 int output_on
; // \O[0] or \O[1] escape calls
676 virtual void really_transparent_char(unsigned char) = 0;
677 virtual void really_print_line(hunits x
, vunits y
, node
*n
,
678 vunits before
, vunits after
, hunits width
) = 0;
679 virtual void really_begin_page(int pageno
, vunits page_length
) = 0;
680 virtual void really_copy_file(hunits x
, vunits y
, const char *filename
);
681 virtual void really_put_filename(const char *filename
);
682 virtual void really_on();
683 virtual void really_off();
690 void transparent_char(unsigned char);
691 void print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
692 void begin_page(int pageno
, vunits page_length
);
693 void put_filename(const char *filename
);
698 void copy_file(hunits x
, vunits y
, const char *filename
);
701 class suppress_output_file
: public real_output_file
{
703 suppress_output_file();
704 void really_transparent_char(unsigned char);
705 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
706 void really_begin_page(int pageno
, vunits page_length
);
709 class ascii_output_file
: public real_output_file
{
712 void really_transparent_char(unsigned char);
713 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
714 void really_begin_page(int pageno
, vunits page_length
);
715 void outc(unsigned char c
);
716 void outs(const char *s
);
719 void ascii_output_file::outc(unsigned char c
)
724 void ascii_output_file::outs(const char *s
)
734 class troff_output_file
: public real_output_file
{
743 tfont
*current_tfont
;
744 color
*current_fill_color
;
745 color
*current_glyph_color
;
746 int current_font_number
;
747 symbol
*font_position
;
749 enum { TBUF_SIZE
= 256 };
750 char tbuf
[TBUF_SIZE
];
756 void put(unsigned char c
);
758 void put(unsigned int i
);
759 void put(const char *s
);
760 void set_font(tfont
*tf
);
764 ~troff_output_file();
765 void trailer(vunits page_length
);
766 void put_char(charinfo
*, tfont
*, color
*, color
*);
767 void put_char_width(charinfo
*, tfont
*, color
*, color
*, hunits
, hunits
);
770 void moveto(hunits
, vunits
);
771 void start_special(tfont
*, color
*, color
*, int = 0);
772 void start_special();
773 void special_char(unsigned char c
);
776 void really_transparent_char(unsigned char c
);
777 void really_print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
778 void really_begin_page(int pageno
, vunits page_length
);
779 void really_copy_file(hunits x
, vunits y
, const char *filename
);
780 void really_put_filename(const char *filename
);
783 void draw(char, hvpair
*, int, font_size
, color
*, color
*);
784 void determine_line_limits (char code
, hvpair
*point
, int npoints
);
785 void check_charinfo(tfont
*tf
, charinfo
*ci
);
786 void glyph_color(color
*c
);
787 void fill_color(color
*c
);
788 int get_hpos() { return hpos
; }
789 int get_vpos() { return vpos
; }
790 friend void space_char_hmotion_node::tprint(troff_output_file
*);
791 friend void unbreakable_space_node::tprint(troff_output_file
*);
794 static void put_string(const char *s
, FILE *fp
)
796 for (; *s
!= '\0'; ++s
)
800 inline void troff_output_file::put(char c
)
805 inline void troff_output_file::put(unsigned char c
)
810 inline void troff_output_file::put(const char *s
)
815 inline void troff_output_file::put(int i
)
817 put_string(i_to_a(i
), fp
);
820 inline void troff_output_file::put(unsigned int i
)
822 put_string(ui_to_a(i
), fp
);
825 void troff_output_file::start_special(tfont
*tf
, color
*gcol
, color
*fcol
,
837 void troff_output_file::start_special()
844 void troff_output_file::special_char(unsigned char c
)
851 void troff_output_file::end_special()
856 inline void troff_output_file::moveto(hunits h
, vunits v
)
862 void troff_output_file::really_print_line(hunits x
, vunits y
, node
*n
,
863 vunits before
, vunits after
, hunits
)
871 // This ensures that transparent throughput will have a more predictable
877 put(before
.to_units());
879 put(after
.to_units());
883 inline void troff_output_file::word_marker()
890 inline void troff_output_file::right(hunits n
)
892 hpos
+= n
.to_units();
895 inline void troff_output_file::down(vunits n
)
897 vpos
+= n
.to_units();
900 void troff_output_file::do_motion()
911 if (hpos
!= output_hpos
) {
912 units n
= hpos
- output_hpos
;
913 if (n
> 0 && n
< hpos
) {
923 if (vpos
!= output_vpos
) {
924 units n
= vpos
- output_vpos
;
925 if (n
> 0 && n
< vpos
) {
941 void troff_output_file::flush_tbuf()
957 check_output_limits(hpos
, vpos
);
958 check_output_limits(hpos
, vpos
- current_size
);
960 for (int i
= 0; i
< tbuf_len
; i
++)
966 void troff_output_file::check_charinfo(tfont
*tf
, charinfo
*ci
)
971 int height
= tf
->get_char_height(ci
).to_units();
972 int width
= tf
->get_width(ci
).to_units()
973 + tf
->get_italic_correction(ci
).to_units();
974 int depth
= tf
->get_char_depth(ci
).to_units();
975 check_output_limits(output_hpos
, output_vpos
- height
);
976 check_output_limits(output_hpos
+ width
, output_vpos
+ depth
);
979 void troff_output_file::put_char_width(charinfo
*ci
, tfont
*tf
,
980 color
*gcol
, color
*fcol
,
983 int kk
= k
.to_units();
986 hpos
+= w
.to_units() + kk
;
990 char c
= ci
->get_ascii_code();
996 check_charinfo(tf
, ci
);
997 if (ci
->numbered()) {
999 put(ci
->get_number());
1003 const char *s
= ci
->nm
.contents();
1012 hpos
+= w
.to_units() + kk
;
1014 else if (tcommand_flag
) {
1015 if (tbuf_len
> 0 && hpos
== output_hpos
&& vpos
== output_vpos
1016 && (!gcol
|| gcol
== current_glyph_color
)
1017 && (!fcol
|| fcol
== current_fill_color
)
1019 && tbuf_len
< TBUF_SIZE
) {
1020 check_charinfo(tf
, ci
);
1021 tbuf
[tbuf_len
++] = c
;
1022 output_hpos
+= w
.to_units() + kk
;
1030 check_charinfo(tf
, ci
);
1031 tbuf
[tbuf_len
++] = c
;
1032 output_hpos
+= w
.to_units() + kk
;
1038 int n
= hpos
- output_hpos
;
1039 check_charinfo(tf
, ci
);
1040 // check_output_limits(output_hpos, output_vpos);
1041 if (vpos
== output_vpos
1042 && (!gcol
|| gcol
== current_glyph_color
)
1043 && (!fcol
|| fcol
== current_fill_color
)
1044 && n
> 0 && n
< 100 && !force_motion
) {
1045 put(char(n
/10 + '0'));
1046 put(char(n
%10 + '0'));
1057 hpos
+= w
.to_units() + kk
;
1061 void troff_output_file::put_char(charinfo
*ci
, tfont
*tf
,
1062 color
*gcol
, color
*fcol
)
1068 char c
= ci
->get_ascii_code();
1074 if (ci
->numbered()) {
1076 put(ci
->get_number());
1080 const char *s
= ci
->nm
.contents();
1091 int n
= hpos
- output_hpos
;
1092 if (vpos
== output_vpos
1093 && (!gcol
|| gcol
== current_glyph_color
)
1094 && (!fcol
|| fcol
== current_fill_color
)
1095 && n
> 0 && n
< 100) {
1096 put(char(n
/10 + '0'));
1097 put(char(n
%10 + '0'));
1112 // set_font calls `flush_tbuf' if necessary.
1114 void troff_output_file::set_font(tfont
*tf
)
1116 if (current_tfont
== tf
)
1119 int n
= tf
->get_input_position();
1120 symbol nm
= tf
->get_name();
1121 if (n
>= nfont_positions
|| font_position
[n
] != nm
) {
1127 if (n
>= nfont_positions
) {
1128 int old_nfont_positions
= nfont_positions
;
1129 symbol
*old_font_position
= font_position
;
1130 nfont_positions
*= 3;
1131 nfont_positions
/= 2;
1132 if (nfont_positions
<= n
)
1133 nfont_positions
= n
+ 10;
1134 font_position
= new symbol
[nfont_positions
];
1135 memcpy(font_position
, old_font_position
,
1136 old_nfont_positions
*sizeof(symbol
));
1137 a_delete old_font_position
;
1139 font_position
[n
] = nm
;
1141 if (current_font_number
!= n
) {
1145 current_font_number
= n
;
1147 int size
= tf
->get_size().to_scaled_points();
1148 if (current_size
!= size
) {
1152 current_size
= size
;
1154 int slant
= tf
->get_slant();
1155 if (current_slant
!= slant
) {
1159 current_slant
= slant
;
1161 int height
= tf
->get_height();
1162 if (current_height
!= height
) {
1164 put(height
== 0 ? current_size
: height
);
1166 current_height
= height
;
1171 // fill_color calls `flush_tbuf' and `do_motion' if necessary.
1173 void troff_output_file::fill_color(color
*col
)
1175 if (!col
|| current_fill_color
== col
)
1177 current_fill_color
= col
;
1183 unsigned int components
[4];
1185 cs
= col
->get_components(components
);
1224 // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1226 void troff_output_file::glyph_color(color
*col
)
1228 if (!col
|| current_glyph_color
== col
)
1230 current_glyph_color
= col
;
1234 // grotty doesn't like a color command if the vertical position is zero.
1237 unsigned int components
[4];
1239 cs
= col
->get_components(components
);
1278 // determine_line_limits - works out the smallest box which will contain
1279 // the entity, code, built from the point array.
1280 void troff_output_file::determine_line_limits(char code
, hvpair
*point
,
1291 // only the h field is used when defining a circle
1292 check_output_limits(output_hpos
,
1293 output_vpos
- point
[0].h
.to_units()/2);
1294 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1295 output_vpos
+ point
[0].h
.to_units()/2);
1299 check_output_limits(output_hpos
,
1300 output_vpos
- point
[0].v
.to_units()/2);
1301 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1302 output_vpos
+ point
[0].v
.to_units()/2);
1308 check_output_limits(x
, y
);
1309 for (i
= 0; i
< npoints
; i
++) {
1310 x
+= point
[i
].h
.to_units();
1311 y
+= point
[i
].v
.to_units();
1312 check_output_limits(x
, y
);
1318 for (i
= 0; i
< npoints
; i
++) {
1319 x
+= point
[i
].h
.to_units();
1320 y
+= point
[i
].v
.to_units();
1321 check_output_limits(x
, y
);
1327 int minx
, miny
, maxx
, maxy
;
1330 p
[0] = point
[0].h
.to_units();
1331 p
[1] = point
[0].v
.to_units();
1332 p
[2] = point
[1].h
.to_units();
1333 p
[3] = point
[1].v
.to_units();
1334 if (adjust_arc_center(p
, c
)) {
1335 check_output_arc_limits(x
, y
,
1336 p
[0], p
[1], p
[2], p
[3],
1338 &minx
, &maxx
, &miny
, &maxy
);
1339 check_output_limits(minx
, miny
);
1340 check_output_limits(maxx
, maxy
);
1347 check_output_limits(x
, y
);
1348 for (i
= 0; i
< npoints
; i
++) {
1349 x
+= point
[i
].h
.to_units();
1350 y
+= point
[i
].v
.to_units();
1351 check_output_limits(x
, y
);
1357 for (i
= 0; i
< npoints
; i
++) {
1358 x
+= point
[i
].h
.to_units();
1359 y
+= point
[i
].v
.to_units();
1360 check_output_limits(x
, y
);
1365 void troff_output_file::draw(char code
, hvpair
*point
, int npoints
,
1366 font_size fsize
, color
*gcol
, color
*fcol
)
1374 int size
= fsize
.to_scaled_points();
1375 if (current_size
!= size
) {
1379 current_size
= size
;
1386 put(point
[0].h
.to_units());
1389 for (i
= 0; i
< npoints
; i
++) {
1391 put(point
[i
].h
.to_units());
1393 put(point
[i
].v
.to_units());
1395 determine_line_limits(code
, point
, npoints
);
1398 for (i
= 0; i
< npoints
; i
++)
1399 output_hpos
+= point
[i
].h
.to_units();
1402 for (i
= 0; i
< npoints
; i
++)
1403 output_vpos
+= point
[i
].v
.to_units();
1410 void troff_output_file::really_on()
1417 void troff_output_file::really_off()
1422 void troff_output_file::really_put_filename(const char *filename
)
1430 void troff_output_file::really_begin_page(int pageno
, vunits page_length
)
1434 if (page_length
> V0
) {
1436 put(page_length
.to_units());
1443 current_font_number
= -1;
1445 // current_height = 0;
1446 // current_slant = 0;
1452 for (int i
= 0; i
< nfont_positions
; i
++)
1453 font_position
[i
] = NULL_SYMBOL
;
1459 void troff_output_file::really_copy_file(hunits x
, vunits y
,
1460 const char *filename
)
1466 FILE *ifp
= include_search_path
.open_file_cautious(filename
);
1468 error("can't open `%1': %2", filename
, strerror(errno
));
1471 while ((c
= getc(ifp
)) != EOF
)
1478 current_font_number
= -1;
1479 for (int i
= 0; i
< nfont_positions
; i
++)
1480 font_position
[i
] = NULL_SYMBOL
;
1483 void troff_output_file::really_transparent_char(unsigned char c
)
1488 troff_output_file::~troff_output_file()
1490 a_delete font_position
;
1493 void troff_output_file::trailer(vunits page_length
)
1496 if (page_length
> V0
) {
1499 put(page_length
.to_units());
1505 troff_output_file::troff_output_file()
1506 : current_slant(0), current_height(0), current_fill_color(0),
1507 current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0)
1509 font_position
= new symbol
[nfont_positions
];
1514 put(units_per_inch
);
1525 output_file
*the_output
= 0;
1527 output_file::output_file()
1531 output_file::~output_file()
1535 void output_file::trailer(vunits
)
1539 void output_file::put_filename(const char *)
1543 void output_file::on()
1547 void output_file::off()
1551 real_output_file::real_output_file()
1552 : printing(0), output_on(1)
1554 #ifndef POPEN_MISSING
1556 if ((fp
= popen(pipe_command
, POPEN_WT
)) != 0) {
1560 error("pipe open failed: %1", strerror(errno
));
1563 #endif /* not POPEN_MISSING */
1567 real_output_file::~real_output_file()
1571 // To avoid looping, set fp to 0 before calling fatal().
1572 if (ferror(fp
) || fflush(fp
) < 0) {
1574 fatal("error writing output file");
1576 #ifndef POPEN_MISSING
1578 int result
= pclose(fp
);
1581 fatal("pclose failed");
1582 if (!WIFEXITED(result
))
1583 error("output process `%1' got fatal signal %2",
1585 WIFSIGNALED(result
) ? WTERMSIG(result
) : WSTOPSIG(result
));
1587 int exit_status
= WEXITSTATUS(result
);
1588 if (exit_status
!= 0)
1589 error("output process `%1' exited with status %2",
1590 pipe_command
, exit_status
);
1594 #endif /* not POPEN MISSING */
1595 if (fclose(fp
) < 0) {
1597 fatal("error closing output file");
1601 void real_output_file::flush()
1604 fatal("error writing output file");
1607 int real_output_file::is_printing()
1612 void real_output_file::begin_page(int pageno
, vunits page_length
)
1614 printing
= in_output_page_list(pageno
);
1616 really_begin_page(pageno
, page_length
);
1619 void real_output_file::copy_file(hunits x
, vunits y
, const char *filename
)
1621 if (printing
&& output_on
)
1622 really_copy_file(x
, y
, filename
);
1623 check_output_limits(x
.to_units(), y
.to_units());
1626 void real_output_file::transparent_char(unsigned char c
)
1628 if (printing
&& output_on
)
1629 really_transparent_char(c
);
1632 void real_output_file::print_line(hunits x
, vunits y
, node
*n
,
1633 vunits before
, vunits after
, hunits width
)
1636 really_print_line(x
, y
, n
, before
, after
, width
);
1637 delete_node_list(n
);
1640 void real_output_file::really_copy_file(hunits
, vunits
, const char *)
1645 void real_output_file::put_filename(const char *filename
)
1647 really_put_filename(filename
);
1650 void real_output_file::really_put_filename(const char *)
1654 void real_output_file::on()
1661 void real_output_file::off()
1667 int real_output_file::is_on()
1672 void real_output_file::really_on()
1676 void real_output_file::really_off()
1680 /* ascii_output_file */
1682 void ascii_output_file::really_transparent_char(unsigned char c
)
1687 void ascii_output_file::really_print_line(hunits
, vunits
, node
*n
,
1688 vunits
, vunits
, hunits
)
1691 n
->ascii_print(this);
1697 void ascii_output_file::really_begin_page(int /*pageno*/, vunits
/*page_length*/)
1699 fputs("<beginning of page>\n", fp
);
1702 ascii_output_file::ascii_output_file()
1706 /* suppress_output_file */
1708 suppress_output_file::suppress_output_file()
1712 void suppress_output_file::really_print_line(hunits
, vunits
, node
*, vunits
, vunits
, hunits
)
1716 void suppress_output_file::really_begin_page(int, vunits
)
1720 void suppress_output_file::really_transparent_char(unsigned char)
1724 /* glyphs, ligatures, kerns, discretionary breaks */
1726 class charinfo_node
: public node
{
1730 charinfo_node(charinfo
*, node
* = 0);
1731 int ends_sentence();
1732 int overlaps_vertically();
1733 int overlaps_horizontally();
1736 charinfo_node::charinfo_node(charinfo
*c
, node
*x
)
1741 int charinfo_node::ends_sentence()
1743 if (ci
->ends_sentence())
1745 else if (ci
->transparent())
1751 int charinfo_node::overlaps_horizontally()
1753 return ci
->overlaps_horizontally();
1756 int charinfo_node::overlaps_vertically()
1758 return ci
->overlaps_vertically();
1761 class glyph_node
: public charinfo_node
{
1762 static glyph_node
*free_list
;
1766 color
*fcol
; /* this is needed for grotty */
1769 glyph_node(charinfo
*, tfont
*, color
*, color
*, hunits
, node
* = 0);
1772 void *operator new(size_t);
1773 void operator delete(void *);
1774 glyph_node(charinfo
*, tfont
*, color
*, color
*, node
* = 0);
1777 node
*merge_glyph_node(glyph_node
*);
1778 node
*merge_self(node
*);
1780 node
*last_char_node();
1782 void vertical_extent(vunits
*, vunits
*);
1783 hunits
subscript_correction();
1784 hunits
italic_correction();
1785 hunits
left_italic_correction();
1787 hyphenation_type
get_hyphenation_type();
1789 color
*get_glyph_color();
1790 color
*get_fill_color();
1791 void tprint(troff_output_file
*);
1792 void zero_width_tprint(troff_output_file
*);
1793 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1794 node
*add_self(node
*, hyphen_list
**);
1795 void ascii_print(ascii_output_file
*);
1796 void asciify(macro
*);
1797 int character_type();
1803 glyph_node
*glyph_node::free_list
= 0;
1805 class ligature_node
: public glyph_node
{
1809 ligature_node(charinfo
*, tfont
*, color
*, color
*, hunits
,
1810 node
*, node
*, node
* = 0);
1813 void *operator new(size_t);
1814 void operator delete(void *);
1815 ligature_node(charinfo
*, tfont
*, color
*, color
*,
1816 node
*, node
*, node
* = 0);
1819 node
*add_self(node
*, hyphen_list
**);
1820 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1821 void ascii_print(ascii_output_file
*);
1822 void asciify(macro
*);
1828 class kern_pair_node
: public node
{
1833 kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
= 0);
1836 node
*merge_glyph_node(glyph_node
*);
1837 node
*add_self(node
*, hyphen_list
**);
1838 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1839 node
*add_discretionary_hyphen();
1841 node
*last_char_node();
1842 hunits
italic_correction();
1843 hunits
subscript_correction();
1844 void tprint(troff_output_file
*);
1845 hyphenation_type
get_hyphenation_type();
1846 int ends_sentence();
1847 void ascii_print(ascii_output_file
*);
1848 void asciify(macro
*);
1852 void vertical_extent(vunits
*, vunits
*);
1855 class dbreak_node
: public node
{
1860 dbreak_node(node
*n
, node
*p
, node
*x
= 0);
1863 node
*merge_glyph_node(glyph_node
*);
1864 node
*add_discretionary_hyphen();
1866 node
*last_char_node();
1867 hunits
italic_correction();
1868 hunits
subscript_correction();
1869 void tprint(troff_output_file
*);
1870 breakpoint
*get_breakpoints(hunits width
, int ns
, breakpoint
*rest
= 0,
1873 int ends_sentence();
1874 void split(int, node
**, node
**);
1875 hyphenation_type
get_hyphenation_type();
1876 void ascii_print(ascii_output_file
*);
1877 void asciify(macro
*);
1883 void *glyph_node::operator new(size_t n
)
1885 assert(n
== sizeof(glyph_node
));
1887 const int BLOCK
= 1024;
1888 free_list
= (glyph_node
*)new char[sizeof(glyph_node
)*BLOCK
];
1889 for (int i
= 0; i
< BLOCK
- 1; i
++)
1890 free_list
[i
].next
= free_list
+ i
+ 1;
1891 free_list
[BLOCK
-1].next
= 0;
1893 glyph_node
*p
= free_list
;
1894 free_list
= (glyph_node
*)(free_list
->next
);
1899 void *ligature_node::operator new(size_t n
)
1904 void glyph_node::operator delete(void *p
)
1907 ((glyph_node
*)p
)->next
= free_list
;
1908 free_list
= (glyph_node
*)p
;
1912 void ligature_node::operator delete(void *p
)
1917 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
, node
*x
)
1918 : charinfo_node(c
, x
), tf(t
), gcol(gc
), fcol(fc
)
1921 wid
= tf
->get_width(ci
);
1926 glyph_node::glyph_node(charinfo
*c
, tfont
*t
,
1927 color
*gc
, color
*fc
, hunits w
, node
*x
)
1928 : charinfo_node(c
, x
), tf(t
), gcol(gc
), fcol(fc
), wid(w
)
1933 node
*glyph_node::copy()
1936 return new glyph_node(ci
, tf
, gcol
, fcol
, wid
);
1938 return new glyph_node(ci
, tf
, gcol
, fcol
);
1942 node
*glyph_node::merge_self(node
*nd
)
1944 return nd
->merge_glyph_node(this);
1947 int glyph_node::character_type()
1949 return tf
->get_character_type(ci
);
1952 node
*glyph_node::add_self(node
*n
, hyphen_list
**p
)
1954 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
1957 if (n
== 0 || (nn
= n
->merge_glyph_node(this)) == 0) {
1962 nn
= nn
->add_discretionary_hyphen();
1963 hyphen_list
*pp
= *p
;
1969 units
glyph_node::size()
1971 return tf
->get_size().to_units();
1974 hyphen_list
*glyph_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
1977 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
1980 tfont
*node::get_tfont()
1985 tfont
*glyph_node::get_tfont()
1990 color
*node::get_glyph_color()
1995 color
*glyph_node::get_glyph_color()
2000 color
*node::get_fill_color()
2005 color
*glyph_node::get_fill_color()
2010 node
*node::merge_glyph_node(glyph_node
*)
2015 node
*glyph_node::merge_glyph_node(glyph_node
*gn
)
2017 if (tf
== gn
->tf
&& gcol
== gn
->gcol
&& fcol
== gn
->fcol
) {
2019 if ((lig
= tf
->get_lig(ci
, gn
->ci
)) != 0) {
2022 return new ligature_node(lig
, tf
, gcol
, fcol
, this, gn
, next1
);
2025 if (tf
->get_kern(ci
, gn
->ci
, &kern
)) {
2028 return new kern_pair_node(kern
, this, gn
, next1
);
2037 hunits
glyph_node::width()
2042 return tf
->get_width(ci
);
2046 node
*glyph_node::last_char_node()
2051 void glyph_node::vertical_extent(vunits
*min
, vunits
*max
)
2053 *min
= -tf
->get_char_height(ci
);
2054 *max
= tf
->get_char_depth(ci
);
2057 hunits
glyph_node::skew()
2059 return tf
->get_char_skew(ci
);
2062 hunits
glyph_node::subscript_correction()
2064 return tf
->get_subscript_correction(ci
);
2067 hunits
glyph_node::italic_correction()
2069 return tf
->get_italic_correction(ci
);
2072 hunits
glyph_node::left_italic_correction()
2074 return tf
->get_left_italic_correction(ci
);
2077 hyphenation_type
glyph_node::get_hyphenation_type()
2079 return HYPHEN_MIDDLE
;
2082 void glyph_node::ascii_print(ascii_output_file
*ascii
)
2084 unsigned char c
= ci
->get_ascii_code();
2088 ascii
->outs(ci
->nm
.contents());
2091 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2092 node
*gn1
, node
*gn2
, node
*x
)
2093 : glyph_node(c
, t
, gc
, fc
, x
), n1(gn1
), n2(gn2
)
2098 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2099 hunits w
, node
*gn1
, node
*gn2
, node
*x
)
2100 : glyph_node(c
, t
, gc
, fc
, w
, x
), n1(gn1
), n2(gn2
)
2105 ligature_node::~ligature_node()
2111 node
*ligature_node::copy()
2114 return new ligature_node(ci
, tf
, gcol
, fcol
, wid
, n1
->copy(), n2
->copy());
2116 return new ligature_node(ci
, tf
, gcol
, fcol
, n1
->copy(), n2
->copy());
2120 void ligature_node::ascii_print(ascii_output_file
*ascii
)
2122 n1
->ascii_print(ascii
);
2123 n2
->ascii_print(ascii
);
2126 hyphen_list
*ligature_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2128 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2129 return n1
->get_hyphen_list(hl
, count
);
2132 node
*ligature_node::add_self(node
*n
, hyphen_list
**p
)
2134 n
= n1
->add_self(n
, p
);
2135 n
= n2
->add_self(n
, p
);
2141 kern_pair_node::kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
)
2142 : node(x
), amount(n
), n1(first
), n2(second
)
2146 dbreak_node::dbreak_node(node
*n
, node
*p
, node
*x
)
2147 : node(x
), none(n
), pre(p
), post(0)
2151 node
*dbreak_node::merge_glyph_node(glyph_node
*gn
)
2153 glyph_node
*gn2
= (glyph_node
*)gn
->copy();
2154 node
*new_none
= none
? none
->merge_glyph_node(gn
) : 0;
2155 node
*new_post
= post
? post
->merge_glyph_node(gn2
) : 0;
2156 if (new_none
== 0 && new_post
== 0) {
2175 node
*kern_pair_node::merge_glyph_node(glyph_node
*gn
)
2177 node
*nd
= n2
->merge_glyph_node(gn
);
2181 nd
= n2
->merge_self(n1
);
2192 hunits
kern_pair_node::italic_correction()
2194 return n2
->italic_correction();
2197 hunits
kern_pair_node::subscript_correction()
2199 return n2
->subscript_correction();
2202 void kern_pair_node::vertical_extent(vunits
*min
, vunits
*max
)
2204 n1
->vertical_extent(min
, max
);
2206 n2
->vertical_extent(&min2
, &max2
);
2213 node
*kern_pair_node::add_discretionary_hyphen()
2215 tfont
*tf
= n2
->get_tfont();
2217 if (tf
->contains(soft_hyphen_char
)) {
2218 color
*gcol
= n2
->get_glyph_color();
2219 color
*fcol
= n2
->get_fill_color();
2223 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
);
2224 node
*nn
= n
->merge_glyph_node(gn
);
2229 return new dbreak_node(this, nn
, next1
);
2235 kern_pair_node::~kern_pair_node()
2243 dbreak_node::~dbreak_node()
2245 delete_node_list(pre
);
2246 delete_node_list(post
);
2247 delete_node_list(none
);
2250 node
*kern_pair_node::copy()
2252 return new kern_pair_node(amount
, n1
->copy(), n2
->copy());
2255 node
*copy_node_list(node
*n
)
2259 node
*nn
= n
->copy();
2273 void delete_node_list(node
*n
)
2282 node
*dbreak_node::copy()
2284 dbreak_node
*p
= new dbreak_node(copy_node_list(none
), copy_node_list(pre
));
2285 p
->post
= copy_node_list(post
);
2289 hyphen_list
*node::get_hyphen_list(hyphen_list
*tail
, int *)
2294 hyphen_list
*kern_pair_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2296 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2297 return n1
->get_hyphen_list(hl
, count
);
2300 class hyphen_inhibitor_node
: public node
{
2302 hyphen_inhibitor_node(node
*nd
= 0);
2307 hyphenation_type
get_hyphenation_type();
2310 hyphen_inhibitor_node::hyphen_inhibitor_node(node
*nd
) : node(nd
)
2314 node
*hyphen_inhibitor_node::copy()
2316 return new hyphen_inhibitor_node
;
2319 int hyphen_inhibitor_node::same(node
*)
2324 const char *hyphen_inhibitor_node::type()
2326 return "hyphen_inhibitor_node";
2329 int hyphen_inhibitor_node::force_tprint()
2334 hyphenation_type
hyphen_inhibitor_node::get_hyphenation_type()
2336 return HYPHEN_INHIBIT
;
2339 /* add_discretionary_hyphen methods */
2341 node
*dbreak_node::add_discretionary_hyphen()
2344 post
= post
->add_discretionary_hyphen();
2346 none
= none
->add_discretionary_hyphen();
2350 node
*node::add_discretionary_hyphen()
2352 tfont
*tf
= get_tfont();
2354 return new hyphen_inhibitor_node(this);
2355 if (tf
->contains(soft_hyphen_char
)) {
2356 color
*gcol
= get_glyph_color();
2357 color
*fcol
= get_fill_color();
2361 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
);
2362 node
*n1
= n
->merge_glyph_node(gn
);
2367 return new dbreak_node(this, n1
, next1
);
2372 node
*node::merge_self(node
*)
2377 node
*node::add_self(node
*n
, hyphen_list
** /*p*/)
2383 node
*kern_pair_node::add_self(node
*n
, hyphen_list
**p
)
2385 n
= n1
->add_self(n
, p
);
2386 n
= n2
->add_self(n
, p
);
2392 hunits
node::width()
2397 node
*node::last_char_node()
2402 int node::force_tprint()
2407 hunits
hmotion_node::width()
2414 return points_to_units(10);
2417 hunits
kern_pair_node::width()
2419 return n1
->width() + n2
->width() + amount
;
2422 node
*kern_pair_node::last_char_node()
2424 node
*nd
= n2
->last_char_node();
2427 return n1
->last_char_node();
2430 hunits
dbreak_node::width()
2433 for (node
*n
= none
; n
!= 0; n
= n
->next
)
2438 node
*dbreak_node::last_char_node()
2440 for (node
*n
= none
; n
; n
= n
->next
) {
2441 node
*last
= n
->last_char_node();
2448 hunits
dbreak_node::italic_correction()
2450 return none
? none
->italic_correction() : H0
;
2453 hunits
dbreak_node::subscript_correction()
2455 return none
? none
->subscript_correction() : H0
;
2458 class italic_corrected_node
: public node
{
2462 italic_corrected_node(node
*, hunits
, node
* = 0);
2463 ~italic_corrected_node();
2465 void ascii_print(ascii_output_file
*);
2466 void asciify(macro
*);
2468 node
*last_char_node();
2469 void vertical_extent(vunits
*, vunits
*);
2470 int ends_sentence();
2471 int overlaps_horizontally();
2472 int overlaps_vertically();
2474 hyphenation_type
get_hyphenation_type();
2476 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2477 int character_type();
2478 void tprint(troff_output_file
*);
2479 hunits
subscript_correction();
2481 node
*add_self(node
*, hyphen_list
**);
2486 node
*node::add_italic_correction(hunits
*width
)
2488 hunits ic
= italic_correction();
2495 return new italic_corrected_node(this, ic
, next1
);
2499 italic_corrected_node::italic_corrected_node(node
*nn
, hunits xx
, node
*p
)
2500 : node(p
), n(nn
), x(xx
)
2505 italic_corrected_node::~italic_corrected_node()
2510 node
*italic_corrected_node::copy()
2512 return new italic_corrected_node(n
->copy(), x
);
2515 hunits
italic_corrected_node::width()
2517 return n
->width() + x
;
2520 void italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
2522 n
->vertical_extent(min
, max
);
2525 void italic_corrected_node::tprint(troff_output_file
*out
)
2531 hunits
italic_corrected_node::skew()
2533 return n
->skew() - x
/2;
2536 hunits
italic_corrected_node::subscript_correction()
2538 return n
->subscript_correction() - x
;
2541 void italic_corrected_node::ascii_print(ascii_output_file
*out
)
2543 n
->ascii_print(out
);
2546 int italic_corrected_node::ends_sentence()
2548 return n
->ends_sentence();
2551 int italic_corrected_node::overlaps_horizontally()
2553 return n
->overlaps_horizontally();
2556 int italic_corrected_node::overlaps_vertically()
2558 return n
->overlaps_vertically();
2561 node
*italic_corrected_node::last_char_node()
2563 return n
->last_char_node();
2566 tfont
*italic_corrected_node::get_tfont()
2568 return n
->get_tfont();
2571 hyphenation_type
italic_corrected_node::get_hyphenation_type()
2573 return n
->get_hyphenation_type();
2576 node
*italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
2578 nd
= n
->add_self(nd
, p
);
2579 hunits not_interested
;
2580 nd
= nd
->add_italic_correction(¬_interested
);
2586 hyphen_list
*italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
2589 return n
->get_hyphen_list(tail
, count
);
2592 int italic_corrected_node::character_type()
2594 return n
->character_type();
2597 class break_char_node
: public node
{
2602 break_char_node(node
*, int, color
*, node
* = 0);
2606 vunits
vertical_width();
2607 node
*last_char_node();
2608 int character_type();
2609 int ends_sentence();
2610 node
*add_self(node
*, hyphen_list
**);
2611 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2612 void tprint(troff_output_file
*);
2613 void zero_width_tprint(troff_output_file
*);
2614 void ascii_print(ascii_output_file
*);
2615 void asciify(macro
*);
2616 hyphenation_type
get_hyphenation_type();
2617 int overlaps_vertically();
2618 int overlaps_horizontally();
2626 break_char_node::break_char_node(node
*n
, int bc
, color
*c
, node
*x
)
2627 : node(x
), ch(n
), break_code(bc
), col(c
)
2631 break_char_node::~break_char_node()
2636 node
*break_char_node::copy()
2638 return new break_char_node(ch
->copy(), break_code
, col
);
2641 hunits
break_char_node::width()
2646 vunits
break_char_node::vertical_width()
2648 return ch
->vertical_width();
2651 node
*break_char_node::last_char_node()
2653 return ch
->last_char_node();
2656 int break_char_node::character_type()
2658 return ch
->character_type();
2661 int break_char_node::ends_sentence()
2663 return ch
->ends_sentence();
2666 node
*break_char_node::add_self(node
*n
, hyphen_list
**p
)
2668 assert((*p
)->hyphenation_code
== 0);
2669 if ((*p
)->breakable
&& (break_code
& 1)) {
2670 n
= new space_node(H0
, col
, n
);
2675 if ((*p
)->breakable
&& (break_code
& 2)) {
2676 n
= new space_node(H0
, col
, n
);
2679 hyphen_list
*pp
= *p
;
2685 hyphen_list
*break_char_node::get_hyphen_list(hyphen_list
*tail
, int *)
2687 return new hyphen_list(0, tail
);
2690 hyphenation_type
break_char_node::get_hyphenation_type()
2692 return HYPHEN_MIDDLE
;
2695 void break_char_node::ascii_print(ascii_output_file
*ascii
)
2697 ch
->ascii_print(ascii
);
2700 int break_char_node::overlaps_vertically()
2702 return ch
->overlaps_vertically();
2705 int break_char_node::overlaps_horizontally()
2707 return ch
->overlaps_horizontally();
2710 units
break_char_node::size()
2715 tfont
*break_char_node::get_tfont()
2717 return ch
->get_tfont();
2720 node
*extra_size_node::copy()
2722 return new extra_size_node(n
);
2725 node
*vertical_size_node::copy()
2727 return new vertical_size_node(n
);
2730 node
*hmotion_node::copy()
2732 return new hmotion_node(n
, was_tab
, unformat
, col
);
2735 node
*space_char_hmotion_node::copy()
2737 return new space_char_hmotion_node(n
, col
);
2740 node
*vmotion_node::copy()
2742 return new vmotion_node(n
, col
);
2745 node
*dummy_node::copy()
2747 return new dummy_node
;
2750 node
*transparent_dummy_node::copy()
2752 return new transparent_dummy_node
;
2755 hline_node::~hline_node()
2761 node
*hline_node::copy()
2763 return new hline_node(x
, n
? n
->copy() : 0);
2766 hunits
hline_node::width()
2768 return x
< H0
? H0
: x
;
2771 vline_node::~vline_node()
2777 node
*vline_node::copy()
2779 return new vline_node(x
, n
? n
->copy() : 0);
2782 hunits
vline_node::width()
2784 return n
== 0 ? H0
: n
->width();
2787 zero_width_node::zero_width_node(node
*nd
) : n(nd
)
2791 zero_width_node::~zero_width_node()
2793 delete_node_list(n
);
2796 node
*zero_width_node::copy()
2798 return new zero_width_node(copy_node_list(n
));
2801 int node_list_character_type(node
*p
)
2804 for (; p
; p
= p
->next
)
2805 t
|= p
->character_type();
2809 int zero_width_node::character_type()
2811 return node_list_character_type(n
);
2814 void node_list_vertical_extent(node
*p
, vunits
*min
, vunits
*max
)
2818 vunits cur_vpos
= V0
;
2820 for (; p
; p
= p
->next
) {
2821 p
->vertical_extent(&v1
, &v2
);
2828 cur_vpos
+= p
->vertical_width();
2832 void zero_width_node::vertical_extent(vunits
*min
, vunits
*max
)
2834 node_list_vertical_extent(n
, min
, max
);
2837 overstrike_node::overstrike_node() : list(0), max_width(H0
)
2841 overstrike_node::~overstrike_node()
2843 delete_node_list(list
);
2846 node
*overstrike_node::copy()
2848 overstrike_node
*on
= new overstrike_node
;
2849 for (node
*tem
= list
; tem
; tem
= tem
->next
)
2850 on
->overstrike(tem
->copy());
2854 void overstrike_node::overstrike(node
*n
)
2858 hunits w
= n
->width();
2862 for (p
= &list
; *p
; p
= &(*p
)->next
)
2868 hunits
overstrike_node::width()
2873 bracket_node::bracket_node() : list(0), max_width(H0
)
2877 bracket_node::~bracket_node()
2879 delete_node_list(list
);
2882 node
*bracket_node::copy()
2884 bracket_node
*on
= new bracket_node
;
2889 for (tem
= list
; tem
; tem
= tem
->next
) {
2891 tem
->next
->last
= tem
;
2894 for (tem
= last
; tem
; tem
= tem
->last
)
2895 on
->bracket(tem
->copy());
2899 void bracket_node::bracket(node
*n
)
2903 hunits w
= n
->width();
2910 hunits
bracket_node::width()
2920 int node::merge_space(hunits
, hunits
, hunits
)
2926 space_node
*space_node::free_list
= 0;
2928 void *space_node::operator new(size_t n
)
2930 assert(n
== sizeof(space_node
));
2932 free_list
= (space_node
*)new char[sizeof(space_node
)*BLOCK
];
2933 for (int i
= 0; i
< BLOCK
- 1; i
++)
2934 free_list
[i
].next
= free_list
+ i
+ 1;
2935 free_list
[BLOCK
-1].next
= 0;
2937 space_node
*p
= free_list
;
2938 free_list
= (space_node
*)(free_list
->next
);
2943 inline void space_node::operator delete(void *p
)
2946 ((space_node
*)p
)->next
= free_list
;
2947 free_list
= (space_node
*)p
;
2952 space_node::space_node(hunits nn
, color
*c
, node
*p
)
2953 : node(p
), n(nn
), set(0), was_escape_colon(0), col(c
)
2957 space_node::space_node(hunits nn
, int s
, int flag
, color
*c
, node
*p
)
2958 : node(p
), n(nn
), set(s
), was_escape_colon(flag
), col(c
)
2963 space_node::~space_node()
2968 node
*space_node::copy()
2970 return new space_node(n
, set
, was_escape_colon
, col
);
2973 int space_node::force_tprint()
2978 int space_node::nspaces()
2983 int space_node::merge_space(hunits h
, hunits
, hunits
)
2989 hunits
space_node::width()
2994 void node::spread_space(int*, hunits
*)
2998 void space_node::spread_space(int *nspaces
, hunits
*desired_space
)
3001 assert(*nspaces
> 0);
3002 if (*nspaces
== 1) {
3003 n
+= *desired_space
;
3004 *desired_space
= H0
;
3007 hunits extra
= *desired_space
/ *nspaces
;
3008 *desired_space
-= extra
;
3016 void node::freeze_space()
3020 void space_node::freeze_space()
3025 void node::is_escape_colon()
3029 void space_node::is_escape_colon()
3031 was_escape_colon
= 1;
3034 diverted_space_node::diverted_space_node(vunits d
, node
*p
)
3039 node
*diverted_space_node::copy()
3041 return new diverted_space_node(n
);
3044 diverted_copy_file_node::diverted_copy_file_node(symbol s
, node
*p
)
3045 : node(p
), filename(s
)
3049 node
*diverted_copy_file_node::copy()
3051 return new diverted_copy_file_node(filename
);
3054 int node::ends_sentence()
3059 int kern_pair_node::ends_sentence()
3061 switch (n2
->ends_sentence()) {
3071 return n1
->ends_sentence();
3074 int node_list_ends_sentence(node
*n
)
3076 for (; n
!= 0; n
= n
->next
)
3077 switch (n
->ends_sentence()) {
3090 int dbreak_node::ends_sentence()
3092 return node_list_ends_sentence(none
);
3095 int node::overlaps_horizontally()
3100 int node::overlaps_vertically()
3105 int node::discardable()
3110 int space_node::discardable()
3115 vunits
node::vertical_width()
3120 vunits
vline_node::vertical_width()
3125 vunits
vmotion_node::vertical_width()
3130 int node::set_unformat_flag()
3135 int node::character_type()
3140 hunits
node::subscript_correction()
3145 hunits
node::italic_correction()
3150 hunits
node::left_italic_correction()
3160 /* vertical_extent methods */
3162 void node::vertical_extent(vunits
*min
, vunits
*max
)
3164 vunits v
= vertical_width();
3175 void vline_node::vertical_extent(vunits
*min
, vunits
*max
)
3178 node::vertical_extent(min
, max
);
3181 n
->vertical_extent(&cmin
, &cmax
);
3182 vunits h
= n
->size();
3189 // we print the first character and then move up, so
3191 // we print the last character and then move up h
3204 // we move down by h and then print the first character, so
3214 /* ascii_print methods */
3216 static void ascii_print_reverse_node_list(ascii_output_file
*ascii
, node
*n
)
3220 ascii_print_reverse_node_list(ascii
, n
->next
);
3221 n
->ascii_print(ascii
);
3224 void dbreak_node::ascii_print(ascii_output_file
*ascii
)
3226 ascii_print_reverse_node_list(ascii
, none
);
3229 void kern_pair_node::ascii_print(ascii_output_file
*ascii
)
3231 n1
->ascii_print(ascii
);
3232 n2
->ascii_print(ascii
);
3235 void node::ascii_print(ascii_output_file
*)
3239 void space_node::ascii_print(ascii_output_file
*ascii
)
3245 void hmotion_node::ascii_print(ascii_output_file
*ascii
)
3247 // this is pretty arbitrary
3248 if (n
>= points_to_units(2))
3252 void space_char_hmotion_node::ascii_print(ascii_output_file
*ascii
)
3257 /* asciify methods */
3259 void node::asciify(macro
*m
)
3264 void glyph_node::asciify(macro
*m
)
3266 unsigned char c
= ci
->get_asciify_code();
3268 c
= ci
->get_ascii_code();
3277 void kern_pair_node::asciify(macro
*m
)
3285 static void asciify_reverse_node_list(macro
*m
, node
*n
)
3289 asciify_reverse_node_list(m
, n
->next
);
3293 void dbreak_node::asciify(macro
*m
)
3295 asciify_reverse_node_list(m
, none
);
3300 void ligature_node::asciify(macro
*m
)
3308 void break_char_node::asciify(macro
*m
)
3315 void italic_corrected_node::asciify(macro
*m
)
3322 void left_italic_corrected_node::asciify(macro
*m
)
3331 void hmotion_node::asciify(macro
*m
)
3341 space_char_hmotion_node::space_char_hmotion_node(hunits i
, color
*c
,
3343 : hmotion_node(i
, c
, next
)
3347 void space_char_hmotion_node::asciify(macro
*m
)
3349 m
->append(ESCAPE_SPACE
);
3353 void space_node::asciify(macro
*m
)
3355 if (was_escape_colon
) {
3356 m
->append(ESCAPE_COLON
);
3363 void word_space_node::asciify(macro
*m
)
3365 for (width_list
*w
= orig_width
; w
; w
= w
->next
)
3370 void unbreakable_space_node::asciify(macro
*m
)
3372 m
->append(ESCAPE_TILDE
);
3376 void line_start_node::asciify(macro
*)
3381 void vertical_size_node::asciify(macro
*)
3386 breakpoint
*node::get_breakpoints(hunits
/*width*/, int /*nspaces*/,
3387 breakpoint
*rest
, int /*is_inner*/)
3397 breakpoint
*space_node::get_breakpoints(hunits width
, int ns
,
3398 breakpoint
*rest
, int is_inner
)
3400 if (next
->discardable())
3402 breakpoint
*bp
= new breakpoint
;
3409 bp
->index
= rest
->index
+ 1;
3419 int space_node::nbreaks()
3421 if (next
->discardable())
3427 static breakpoint
*node_list_get_breakpoints(node
*p
, hunits
*widthp
,
3428 int ns
, breakpoint
*rest
)
3431 rest
= p
->get_breakpoints(*widthp
,
3433 node_list_get_breakpoints(p
->next
, widthp
, ns
,
3436 *widthp
+= p
->width();
3441 breakpoint
*dbreak_node::get_breakpoints(hunits width
, int ns
,
3442 breakpoint
*rest
, int is_inner
)
3444 breakpoint
*bp
= new breakpoint
;
3447 for (node
*tem
= pre
; tem
!= 0; tem
= tem
->next
)
3448 bp
->width
+= tem
->width();
3453 bp
->index
= rest
->index
+ 1;
3460 return node_list_get_breakpoints(none
, &width
, ns
, bp
);
3463 int dbreak_node::nbreaks()
3466 for (node
*tem
= none
; tem
!= 0; tem
= tem
->next
)
3467 i
+= tem
->nbreaks();
3471 void node::split(int /*where*/, node
** /*prep*/, node
** /*postp*/)
3476 void space_node::split(int where
, node
**pre
, node
**post
)
3484 static void node_list_split(node
*p
, int *wherep
, node
**prep
, node
**postp
)
3488 int nb
= p
->nbreaks();
3489 node_list_split(p
->next
, wherep
, prep
, postp
);
3494 else if (*wherep
< nb
) {
3496 p
->split(*wherep
, prep
, postp
);
3505 void dbreak_node::split(int where
, node
**prep
, node
**postp
)
3515 for (tem
= pre
; tem
->next
!= 0; tem
= tem
->next
)
3526 node_list_split(none
, &where
, prep
, postp
);
3532 hyphenation_type
node::get_hyphenation_type()
3534 return HYPHEN_BOUNDARY
;
3537 hyphenation_type
dbreak_node::get_hyphenation_type()
3539 return HYPHEN_INHIBIT
;
3542 hyphenation_type
kern_pair_node::get_hyphenation_type()
3544 return HYPHEN_MIDDLE
;
3547 hyphenation_type
dummy_node::get_hyphenation_type()
3549 return HYPHEN_MIDDLE
;
3552 hyphenation_type
transparent_dummy_node::get_hyphenation_type()
3554 return HYPHEN_MIDDLE
;
3557 hyphenation_type
hmotion_node::get_hyphenation_type()
3559 return HYPHEN_MIDDLE
;
3562 hyphenation_type
space_char_hmotion_node::get_hyphenation_type()
3564 return HYPHEN_MIDDLE
;
3567 hyphenation_type
overstrike_node::get_hyphenation_type()
3569 return HYPHEN_MIDDLE
;
3572 hyphenation_type
space_node::get_hyphenation_type()
3574 if (was_escape_colon
)
3575 return HYPHEN_MIDDLE
;
3576 return HYPHEN_BOUNDARY
;
3579 hyphenation_type
unbreakable_space_node::get_hyphenation_type()
3581 return HYPHEN_MIDDLE
;
3584 int node::interpret(macro
*)
3589 special_node::special_node(const macro
&m
, int n
)
3590 : mac(m
), no_init_string(n
)
3592 font_size fs
= curenv
->get_font_size();
3593 int char_height
= curenv
->get_char_height();
3594 int char_slant
= curenv
->get_char_slant();
3595 int fontno
= env_definite_font(curenv
);
3596 tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fontno
);
3597 if (curenv
->is_composite())
3598 tf
= tf
->get_plain();
3599 gcol
= curenv
->get_glyph_color();
3600 fcol
= curenv
->get_fill_color();
3603 special_node::special_node(const macro
&m
, tfont
*t
,
3604 color
*gc
, color
*fc
, int n
)
3605 : mac(m
), tf(t
), gcol(gc
), fcol(fc
), no_init_string(n
)
3609 int special_node::same(node
*n
)
3611 return mac
== ((special_node
*)n
)->mac
3612 && tf
== ((special_node
*)n
)->tf
3613 && gcol
== ((special_node
*)n
)->gcol
3614 && fcol
== ((special_node
*)n
)->fcol
3615 && no_init_string
== ((special_node
*)n
)->no_init_string
;
3618 const char *special_node::type()
3620 return "special_node";
3623 int special_node::ends_sentence()
3628 int special_node::force_tprint()
3633 node
*special_node::copy()
3635 return new special_node(mac
, tf
, gcol
, fcol
, no_init_string
);
3638 void special_node::tprint_start(troff_output_file
*out
)
3640 out
->start_special(tf
, gcol
, fcol
, no_init_string
);
3643 void special_node::tprint_char(troff_output_file
*out
, unsigned char c
)
3645 out
->special_char(c
);
3648 void special_node::tprint_end(troff_output_file
*out
)
3653 tfont
*special_node::get_tfont()
3660 suppress_node::suppress_node(int on_or_off
, int issue_limits
)
3661 : is_on(on_or_off
), emit_limits(issue_limits
),
3662 filename(0), position(0), image_id(0)
3666 suppress_node::suppress_node(symbol f
, char p
, int id
)
3667 : is_on(2), emit_limits(0), filename(f
), position(p
), image_id(id
)
3671 suppress_node::suppress_node(int issue_limits
, int on_or_off
,
3672 symbol f
, char p
, int id
)
3673 : is_on(on_or_off
), emit_limits(issue_limits
),
3674 filename(f
), position(p
), image_id(id
)
3678 int suppress_node::same(node
*n
)
3680 return ((is_on
== ((suppress_node
*)n
)->is_on
)
3681 && (emit_limits
== ((suppress_node
*)n
)->emit_limits
)
3682 && (filename
== ((suppress_node
*)n
)->filename
)
3683 && (position
== ((suppress_node
*)n
)->position
)
3684 && (image_id
== ((suppress_node
*)n
)->image_id
));
3687 const char *suppress_node::type()
3689 return "suppress_node";
3692 node
*suppress_node::copy()
3694 return new suppress_node(emit_limits
, is_on
, filename
, position
, image_id
);
3697 int get_reg_int(const char *p
)
3699 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
3701 if (r
&& (r
->get_value(&prev_value
)))
3702 return (int)prev_value
;
3704 warning(WARN_REG
, "number register `%1' not defined", p
);
3708 const char *get_reg_str(const char *p
)
3710 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
3712 return r
->get_string();
3714 warning(WARN_REG
, "register `%1' not defined", p
);
3718 void suppress_node::put(troff_output_file
*out
, const char *s
)
3721 while (s
[i
] != (char)0) {
3722 out
->special_char(s
[i
]);
3728 * We need to remember the start of the image and its name.
3731 static char last_position
= 0;
3732 static const char *last_image_filename
= 0;
3733 static int last_image_id
= 0;
3735 inline int min(int a
, int b
)
3737 return a
< b
? a
: b
;
3741 * tprint - if (is_on == 2)
3742 * remember current position (l, r, c, i) and filename
3748 * emit postscript bounds for image
3750 * if (suppress boolean differs from current state)
3753 * record current page
3754 * set low water mark.
3757 void suppress_node::tprint(troff_output_file
*out
)
3759 int current_page
= topdiv
->get_page_number();
3760 // firstly check to see whether this suppress node contains
3761 // an image filename & position.
3763 // remember position and filename
3764 last_position
= position
;
3765 const char *tem
= last_image_filename
;
3766 last_image_filename
= strsave(filename
.contents());
3769 last_image_id
= image_id
;
3770 // printf("start of image and page = %d\n", current_page);
3773 // now check whether the suppress node requires us to issue limits.
3776 // remember that the filename will contain a %d in which the
3777 // last_image_id is placed
3778 sprintf(name
, last_image_filename
, last_image_id
);
3780 switch (last_position
) {
3782 out
->start_special();
3783 put(out
, "html-tag:.centered-image");
3786 out
->start_special();
3787 put(out
, "html-tag:.right-image");
3790 out
->start_special();
3791 put(out
, "html-tag:.left-image");
3799 out
->start_special();
3800 put(out
, "html-tag:.auto-image ");
3805 // postscript (or other device)
3806 if (suppress_start_page
> 0 && current_page
!= suppress_start_page
)
3807 error("suppression limit registers span more than one page;\n"
3808 "image description %1 will be wrong", image_no
);
3809 // if (topdiv->get_page_number() != suppress_start_page)
3810 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
3811 // topdiv->get_page_number(), suppress_start_page);
3813 // remember that the filename will contain a %d in which the
3814 // image_no is placed
3816 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
3817 topdiv
->get_page_number(),
3818 get_reg_int("opminx"), get_reg_int("opminy"),
3819 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
3820 // page offset + line length
3821 get_reg_int(".o") + get_reg_int(".l"),
3822 name
, hresolution
, vresolution
, get_reg_str(".F"));
3829 // lastly we reset the output registers
3830 reset_output_registers();
3834 suppress_start_page
= current_page
;
3839 int suppress_node::force_tprint()
3844 hunits
suppress_node::width()
3849 /* composite_node */
3851 class composite_node
: public charinfo_node
{
3855 composite_node(node
*, charinfo
*, tfont
*, node
* = 0);
3859 node
*last_char_node();
3861 void tprint(troff_output_file
*);
3862 hyphenation_type
get_hyphenation_type();
3863 void ascii_print(ascii_output_file
*);
3864 void asciify(macro
*);
3865 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
3866 node
*add_self(node
*, hyphen_list
**);
3871 void vertical_extent(vunits
*, vunits
*);
3872 vunits
vertical_width();
3875 composite_node::composite_node(node
*p
, charinfo
*c
, tfont
*t
, node
*x
)
3876 : charinfo_node(c
, x
), n(p
), tf(t
)
3880 composite_node::~composite_node()
3882 delete_node_list(n
);
3885 node
*composite_node::copy()
3887 return new composite_node(copy_node_list(n
), ci
, tf
);
3890 hunits
composite_node::width()
3893 if (tf
->get_constant_space(&x
))
3896 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3899 if (tf
->get_bold(&offset
))
3901 x
+= tf
->get_track_kern();
3905 node
*composite_node::last_char_node()
3910 vunits
composite_node::vertical_width()
3913 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3914 v
+= tem
->vertical_width();
3918 units
composite_node::size()
3920 return tf
->get_size().to_units();
3923 hyphenation_type
composite_node::get_hyphenation_type()
3925 return HYPHEN_MIDDLE
;
3928 void composite_node::asciify(macro
*m
)
3930 unsigned char c
= ci
->get_asciify_code();
3932 c
= ci
->get_ascii_code();
3941 void composite_node::ascii_print(ascii_output_file
*ascii
)
3943 unsigned char c
= ci
->get_ascii_code();
3947 ascii
->outs(ci
->nm
.contents());
3951 hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
3954 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
3957 node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
3959 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
3963 nn
= nn
->add_discretionary_hyphen();
3964 hyphen_list
*pp
= *p
;
3970 tfont
*composite_node::get_tfont()
3975 node
*reverse_node_list(node
*n
)
3987 void composite_node::vertical_extent(vunits
*min
, vunits
*max
)
3989 n
= reverse_node_list(n
);
3990 node_list_vertical_extent(n
, min
, max
);
3991 n
= reverse_node_list(n
);
3994 width_list::width_list(hunits w
, hunits s
)
3995 : width(w
), sentence_width(s
), next(0)
3999 width_list::width_list(width_list
*w
)
4000 : width(w
->width
), sentence_width(w
->sentence_width
), next(0)
4004 word_space_node::word_space_node(hunits d
, color
*c
, width_list
*w
, node
*x
)
4005 : space_node(d
, c
, x
), orig_width(w
), unformat(0)
4009 word_space_node::word_space_node(hunits d
, int s
, color
*c
, width_list
*w
,
4011 : space_node(d
, s
, 0, c
, x
), orig_width(w
), unformat(flag
)
4015 word_space_node::~word_space_node()
4017 width_list
*w
= orig_width
;
4019 width_list
*tmp
= w
;
4025 node
*word_space_node::copy()
4027 assert(orig_width
!= 0);
4028 width_list
*w_old_curr
= orig_width
;
4029 width_list
*w_new_curr
= new width_list(w_old_curr
);
4030 width_list
*w_new
= w_new_curr
;
4031 w_old_curr
= w_old_curr
->next
;
4032 while (w_old_curr
!= 0) {
4033 w_new_curr
->next
= new width_list(w_old_curr
);
4034 w_new_curr
= w_new_curr
->next
;
4035 w_old_curr
= w_old_curr
->next
;
4037 return new word_space_node(n
, set
, col
, w_new
, unformat
);
4040 int word_space_node::set_unformat_flag()
4046 void word_space_node::tprint(troff_output_file
*out
)
4048 out
->fill_color(col
);
4053 int word_space_node::merge_space(hunits h
, hunits sw
, hunits ssw
)
4056 assert(orig_width
!= 0);
4057 width_list
*w
= orig_width
;
4058 for (; w
->next
; w
= w
->next
)
4060 w
->next
= new width_list(sw
, ssw
);
4064 unbreakable_space_node::unbreakable_space_node(hunits d
, color
*c
, node
*x
)
4065 : word_space_node(d
, c
, 0, x
)
4069 unbreakable_space_node::unbreakable_space_node(hunits d
, int s
,
4071 : word_space_node(d
, s
, c
, 0, 0, x
)
4075 node
*unbreakable_space_node::copy()
4077 return new unbreakable_space_node(n
, set
, col
);
4080 int unbreakable_space_node::force_tprint()
4085 breakpoint
*unbreakable_space_node::get_breakpoints(hunits
, int,
4086 breakpoint
*rest
, int)
4091 int unbreakable_space_node::nbreaks()
4096 void unbreakable_space_node::split(int, node
**, node
**)
4101 int unbreakable_space_node::merge_space(hunits
, hunits
, hunits
)
4110 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4111 color
*gc
, color
*fc
)
4112 : npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4114 point
= new hvpair
[npoints
];
4115 for (int i
= 0; i
< npoints
; i
++)
4119 int draw_node::same(node
*n
)
4121 draw_node
*nd
= (draw_node
*)n
;
4122 if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
4123 || gcol
!= nd
->gcol
|| fcol
!= nd
->fcol
)
4125 for (int i
= 0; i
< npoints
; i
++)
4126 if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
4131 const char *draw_node::type()
4136 int draw_node::force_tprint()
4141 draw_node::~draw_node()
4147 hunits
draw_node::width()
4150 for (int i
= 0; i
< npoints
; i
++)
4155 vunits
draw_node::vertical_width()
4160 for (int i
= 0; i
< npoints
; i
++)
4165 node
*draw_node::copy()
4167 return new draw_node(code
, point
, npoints
, sz
, gcol
, fcol
);
4170 void draw_node::tprint(troff_output_file
*out
)
4172 out
->draw(code
, point
, npoints
, sz
, gcol
, fcol
);
4175 /* tprint methods */
4177 void glyph_node::tprint(troff_output_file
*out
)
4179 tfont
*ptf
= tf
->get_plain();
4181 out
->put_char_width(ci
, ptf
, gcol
, fcol
, width(), H0
);
4184 int bold
= tf
->get_bold(&offset
);
4185 hunits w
= ptf
->get_width(ci
);
4188 int cs
= tf
->get_constant_space(&x
);
4198 k
= tf
->get_track_kern();
4200 out
->put_char(ci
, ptf
, gcol
, fcol
);
4203 out
->put_char_width(ci
, ptf
, gcol
, fcol
, w
, k
);
4207 void glyph_node::zero_width_tprint(troff_output_file
*out
)
4209 tfont
*ptf
= tf
->get_plain();
4211 int bold
= tf
->get_bold(&offset
);
4213 int cs
= tf
->get_constant_space(&x
);
4215 x
-= ptf
->get_width(ci
);
4221 out
->put_char(ci
, ptf
, gcol
, fcol
);
4224 out
->put_char(ci
, ptf
, gcol
, fcol
);
4225 out
->right(-offset
);
4231 void break_char_node::tprint(troff_output_file
*t
)
4236 void break_char_node::zero_width_tprint(troff_output_file
*t
)
4238 ch
->zero_width_tprint(t
);
4241 void hline_node::tprint(troff_output_file
*out
)
4251 hunits w
= n
->width();
4253 error("horizontal line drawing character must have positive width");
4264 out
->right(xx
- xx2
);
4267 hunits rem
= x
- w
*i
;
4269 if (n
->overlaps_horizontally()) {
4272 out
->right(rem
- w
);
4282 void vline_node::tprint(troff_output_file
*out
)
4288 vunits h
= n
->size();
4289 int overlaps
= n
->overlaps_vertically();
4294 vunits rem
= y
- i
*h
;
4296 out
->right(n
->width());
4301 n
->zero_width_tprint(out
);
4305 n
->zero_width_tprint(out
);
4314 out
->down(-h
- rem
);
4320 vunits rem
= y
- i
*h
;
4323 out
->right(n
->width());
4328 n
->zero_width_tprint(out
);
4331 n
->zero_width_tprint(out
);
4340 void zero_width_node::tprint(troff_output_file
*out
)
4345 n
->zero_width_tprint(out
);
4348 int hpos
= out
->get_hpos();
4349 int vpos
= out
->get_vpos();
4355 out
->moveto(hpos
, vpos
);
4358 void overstrike_node::tprint(troff_output_file
*out
)
4361 for (node
*tem
= list
; tem
; tem
= tem
->next
) {
4362 hunits x
= (max_width
- tem
->width())/2;
4363 out
->right(x
- pos
);
4365 tem
->zero_width_tprint(out
);
4367 out
->right(max_width
- pos
);
4370 void bracket_node::tprint(troff_output_file
*out
)
4376 for (tem
= list
; tem
; tem
= tem
->next
)
4378 vunits h
= list
->size();
4379 vunits totalh
= h
*npieces
;
4380 vunits y
= (totalh
- h
)/2;
4382 for (tem
= list
; tem
; tem
= tem
->next
) {
4383 tem
->zero_width_tprint(out
);
4386 out
->right(max_width
);
4387 out
->down(totalh
- y
);
4390 void node::tprint(troff_output_file
*)
4394 void node::zero_width_tprint(troff_output_file
*out
)
4396 int hpos
= out
->get_hpos();
4397 int vpos
= out
->get_vpos();
4399 out
->moveto(hpos
, vpos
);
4402 void space_node::tprint(troff_output_file
*out
)
4404 out
->fill_color(col
);
4408 void hmotion_node::tprint(troff_output_file
*out
)
4410 out
->fill_color(col
);
4414 void space_char_hmotion_node::tprint(troff_output_file
*out
)
4416 out
->fill_color(col
);
4418 // we emit the space width as a negative glyph index
4422 out
->put(-n
.to_units());
4428 void vmotion_node::tprint(troff_output_file
*out
)
4430 out
->fill_color(col
);
4434 void kern_pair_node::tprint(troff_output_file
*out
)
4441 static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
4445 tprint_reverse_node_list(out
, n
->next
);
4449 void dbreak_node::tprint(troff_output_file
*out
)
4451 tprint_reverse_node_list(out
, none
);
4454 void composite_node::tprint(troff_output_file
*out
)
4457 int is_bold
= tf
->get_bold(&bold_offset
);
4458 hunits track_kern
= tf
->get_track_kern();
4459 hunits constant_space
;
4460 int is_constant_spaced
= tf
->get_constant_space(&constant_space
);
4462 if (is_constant_spaced
) {
4464 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4473 int hpos
= out
->get_hpos();
4474 int vpos
= out
->get_vpos();
4475 tprint_reverse_node_list(out
, n
);
4476 out
->moveto(hpos
, vpos
);
4477 out
->right(bold_offset
);
4479 tprint_reverse_node_list(out
, n
);
4480 if (is_constant_spaced
)
4483 out
->right(track_kern
);
4486 node
*make_composite_node(charinfo
*s
, environment
*env
)
4488 int fontno
= env_definite_font(env
);
4490 error("no current font");
4493 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4494 node
*n
= charinfo_to_node_list(s
, env
);
4495 font_size fs
= env
->get_font_size();
4496 int char_height
= env
->get_char_height();
4497 int char_slant
= env
->get_char_slant();
4498 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
,
4500 if (env
->is_composite())
4501 tf
= tf
->get_plain();
4502 return new composite_node(n
, s
, tf
);
4505 node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
4507 int fontno
= env_definite_font(env
);
4509 error("no current font");
4512 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4514 int found
= font_table
[fontno
]->contains(s
);
4516 macro
*mac
= s
->get_macro();
4517 if (mac
&& s
->is_fallback())
4518 return make_composite_node(s
, env
);
4519 if (s
->numbered()) {
4520 if (!no_error_message
)
4521 warning(WARN_CHAR
, "can't find numbered character %1",
4525 special_font_list
*sf
= font_table
[fontno
]->sf
;
4526 while (sf
!= 0 && !found
) {
4529 found
= font_table
[fn
]->contains(s
);
4533 symbol f
= font_table
[fontno
]->get_name();
4534 string
gl(f
.contents());
4536 gl
+= s
->nm
.contents();
4538 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
4539 if (ci
&& ci
->get_macro())
4540 return make_composite_node(ci
, env
);
4543 sf
= global_special_fonts
;
4544 while (sf
!= 0 && !found
) {
4547 found
= font_table
[fn
]->contains(s
);
4552 if (mac
&& s
->is_special())
4553 return make_composite_node(s
, env
);
4555 for (fn
= 0; fn
< font_table_size
; fn
++)
4557 && font_table
[fn
]->is_special()
4558 && font_table
[fn
]->contains(s
)) {
4564 if (!no_error_message
&& s
->first_time_not_found()) {
4565 unsigned char input_code
= s
->get_ascii_code();
4566 if (input_code
!= 0) {
4567 if (csgraph(input_code
))
4568 warning(WARN_CHAR
, "can't find character `%1'", input_code
);
4570 warning(WARN_CHAR
, "can't find character with input code %1",
4573 else if (s
->nm
.contents())
4574 warning(WARN_CHAR
, "can't find special character `%1'",
4580 font_size fs
= env
->get_font_size();
4581 int char_height
= env
->get_char_height();
4582 int char_slant
= env
->get_char_slant();
4583 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
4584 if (env
->is_composite())
4585 tf
= tf
->get_plain();
4586 color
*gcol
= env
->get_glyph_color();
4587 color
*fcol
= env
->get_fill_color();
4588 return new glyph_node(s
, tf
, gcol
, fcol
);
4591 node
*make_node(charinfo
*ci
, environment
*env
)
4593 switch (ci
->get_special_translation()) {
4594 case charinfo::TRANSLATE_SPACE
:
4595 return new space_char_hmotion_node(env
->get_space_width(),
4596 env
->get_fill_color());
4597 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4598 return new unbreakable_space_node(env
->get_space_width(),
4599 env
->get_fill_color());
4600 case charinfo::TRANSLATE_DUMMY
:
4601 return new dummy_node
;
4602 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4603 error("translation to \\% ignored in this context");
4606 charinfo
*tem
= ci
->get_translation();
4609 macro
*mac
= ci
->get_macro();
4610 if (mac
&& ci
->is_normal())
4611 return make_composite_node(ci
, env
);
4613 return make_glyph_node(ci
, env
);
4616 int character_exists(charinfo
*ci
, environment
*env
)
4618 if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
4620 charinfo
*tem
= ci
->get_translation();
4623 if (ci
->get_macro())
4625 node
*nd
= make_glyph_node(ci
, env
, 1);
4633 node
*node::add_char(charinfo
*ci
, environment
*env
,
4634 hunits
*widthp
, int *spacep
)
4637 switch (ci
->get_special_translation()) {
4638 case charinfo::TRANSLATE_SPACE
:
4639 res
= new space_char_hmotion_node(env
->get_space_width(),
4640 env
->get_fill_color(), this);
4641 *widthp
+= res
->width();
4643 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
4644 res
= new unbreakable_space_node(env
->get_space_width(),
4645 env
->get_fill_color(), this);
4646 res
->freeze_space();
4647 *widthp
+= res
->width();
4648 *spacep
+= res
->nspaces();
4650 case charinfo::TRANSLATE_DUMMY
:
4651 return new dummy_node(this);
4652 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
4653 return add_discretionary_hyphen();
4655 charinfo
*tem
= ci
->get_translation();
4658 macro
*mac
= ci
->get_macro();
4659 if (mac
&& ci
->is_normal()) {
4660 res
= make_composite_node(ci
, env
);
4663 *widthp
+= res
->width();
4669 node
*gn
= make_glyph_node(ci
, env
);
4673 hunits old_width
= width();
4674 node
*p
= gn
->merge_self(this);
4676 *widthp
+= gn
->width();
4681 *widthp
+= p
->width() - old_width
;
4687 if (ci
->can_break_before())
4689 if (ci
->can_break_after())
4692 node
*next1
= res
->next
;
4694 res
= new break_char_node(res
, break_code
, env
->get_fill_color(), next1
);
4702 int same_node(node
*n1
, node
*n2
)
4706 return n1
->type() == n2
->type() && n1
->same(n2
);
4714 int same_node_list(node
*n1
, node
*n2
)
4717 if (n1
->type() != n2
->type() || !n1
->same(n2
))
4725 int extra_size_node::same(node
*nd
)
4727 return n
== ((extra_size_node
*)nd
)->n
;
4730 const char *extra_size_node::type()
4732 return "extra_size_node";
4735 int extra_size_node::force_tprint()
4740 int vertical_size_node::same(node
*nd
)
4742 return n
== ((vertical_size_node
*)nd
)->n
;
4745 const char *vertical_size_node::type()
4747 return "vertical_size_node";
4750 int vertical_size_node::set_unformat_flag()
4755 int vertical_size_node::force_tprint()
4760 int hmotion_node::same(node
*nd
)
4762 return n
== ((hmotion_node
*)nd
)->n
4763 && col
== ((hmotion_node
*)nd
)->col
;
4766 const char *hmotion_node::type()
4768 return "hmotion_node";
4771 int hmotion_node::set_unformat_flag()
4777 int hmotion_node::force_tprint()
4782 node
*hmotion_node::add_self(node
*n
, hyphen_list
**p
)
4785 hyphen_list
*pp
= *p
;
4791 hyphen_list
*hmotion_node::get_hyphen_list(hyphen_list
*tail
, int *)
4793 return new hyphen_list(0, tail
);
4796 int space_char_hmotion_node::same(node
*nd
)
4798 return n
== ((space_char_hmotion_node
*)nd
)->n
4799 && col
== ((space_char_hmotion_node
*)nd
)->col
;
4802 const char *space_char_hmotion_node::type()
4804 return "space_char_hmotion_node";
4807 int space_char_hmotion_node::force_tprint()
4812 node
*space_char_hmotion_node::add_self(node
*n
, hyphen_list
**p
)
4815 hyphen_list
*pp
= *p
;
4821 hyphen_list
*space_char_hmotion_node::get_hyphen_list(hyphen_list
*tail
,
4824 return new hyphen_list(0, tail
);
4827 int vmotion_node::same(node
*nd
)
4829 return n
== ((vmotion_node
*)nd
)->n
4830 && col
== ((vmotion_node
*)nd
)->col
;
4833 const char *vmotion_node::type()
4835 return "vmotion_node";
4838 int vmotion_node::force_tprint()
4843 int hline_node::same(node
*nd
)
4845 return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
4848 const char *hline_node::type()
4850 return "hline_node";
4853 int hline_node::force_tprint()
4858 int vline_node::same(node
*nd
)
4860 return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
4863 const char *vline_node::type()
4865 return "vline_node";
4868 int vline_node::force_tprint()
4873 int dummy_node::same(node
* /*nd*/)
4878 const char *dummy_node::type()
4880 return "dummy_node";
4883 int dummy_node::force_tprint()
4888 int transparent_dummy_node::same(node
* /*nd*/)
4893 const char *transparent_dummy_node::type()
4895 return "transparent_dummy_node";
4898 int transparent_dummy_node::force_tprint()
4903 int transparent_dummy_node::ends_sentence()
4908 int zero_width_node::same(node
*nd
)
4910 return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
4913 const char *zero_width_node::type()
4915 return "zero_width_node";
4918 int zero_width_node::force_tprint()
4923 int italic_corrected_node::same(node
*nd
)
4925 return (x
== ((italic_corrected_node
*)nd
)->x
4926 && same_node(n
, ((italic_corrected_node
*)nd
)->n
));
4929 const char *italic_corrected_node::type()
4931 return "italic_corrected_node";
4934 int italic_corrected_node::force_tprint()
4939 left_italic_corrected_node::left_italic_corrected_node(node
*x
)
4944 left_italic_corrected_node::~left_italic_corrected_node()
4949 node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
4952 hunits lic
= gn
->left_italic_correction();
4953 if (!lic
.is_zero()) {
4960 node
*nd
= n
->merge_glyph_node(gn
);
4963 x
= n
->left_italic_correction();
4970 node
*left_italic_corrected_node::copy()
4972 left_italic_corrected_node
*nd
= new left_italic_corrected_node
;
4980 void left_italic_corrected_node::tprint(troff_output_file
*out
)
4988 const char *left_italic_corrected_node::type()
4990 return "left_italic_corrected_node";
4993 int left_italic_corrected_node::force_tprint()
4998 int left_italic_corrected_node::same(node
*nd
)
5000 return (x
== ((left_italic_corrected_node
*)nd
)->x
5001 && same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
5004 void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
5007 n
->ascii_print(out
);
5010 hunits
left_italic_corrected_node::width()
5012 return n
? n
->width() + x
: H0
;
5015 void left_italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
5018 n
->vertical_extent(min
, max
);
5020 node::vertical_extent(min
, max
);
5023 hunits
left_italic_corrected_node::skew()
5025 return n
? n
->skew() + x
/2 : H0
;
5028 hunits
left_italic_corrected_node::subscript_correction()
5030 return n
? n
->subscript_correction() : H0
;
5033 hunits
left_italic_corrected_node::italic_correction()
5035 return n
? n
->italic_correction() : H0
;
5038 int left_italic_corrected_node::ends_sentence()
5040 return n
? n
->ends_sentence() : 0;
5043 int left_italic_corrected_node::overlaps_horizontally()
5045 return n
? n
->overlaps_horizontally() : 0;
5048 int left_italic_corrected_node::overlaps_vertically()
5050 return n
? n
->overlaps_vertically() : 0;
5053 node
*left_italic_corrected_node::last_char_node()
5055 return n
? n
->last_char_node() : 0;
5058 tfont
*left_italic_corrected_node::get_tfont()
5060 return n
? n
->get_tfont() : 0;
5063 hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
5066 return n
->get_hyphenation_type();
5068 return HYPHEN_MIDDLE
;
5071 hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
5074 return n
? n
->get_hyphen_list(tail
, count
) : tail
;
5077 node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
5080 nd
= new left_italic_corrected_node(nd
);
5081 nd
= n
->add_self(nd
, p
);
5088 int left_italic_corrected_node::character_type()
5090 return n
? n
->character_type() : 0;
5093 int overstrike_node::same(node
*nd
)
5095 return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
5098 const char *overstrike_node::type()
5100 return "overstrike_node";
5103 int overstrike_node::force_tprint()
5108 node
*overstrike_node::add_self(node
*n
, hyphen_list
**p
)
5111 hyphen_list
*pp
= *p
;
5117 hyphen_list
*overstrike_node::get_hyphen_list(hyphen_list
*tail
, int *)
5119 return new hyphen_list(0, tail
);
5122 int bracket_node::same(node
*nd
)
5124 return same_node_list(list
, ((bracket_node
*)nd
)->list
);
5127 const char *bracket_node::type()
5129 return "bracket_node";
5132 int bracket_node::force_tprint()
5137 int composite_node::same(node
*nd
)
5139 return ci
== ((composite_node
*)nd
)->ci
5140 && same_node_list(n
, ((composite_node
*)nd
)->n
);
5143 const char *composite_node::type()
5145 return "composite_node";
5148 int composite_node::force_tprint()
5153 int glyph_node::same(node
*nd
)
5155 return ci
== ((glyph_node
*)nd
)->ci
5156 && tf
== ((glyph_node
*)nd
)->tf
5157 && gcol
== ((glyph_node
*)nd
)->gcol
5158 && fcol
== ((glyph_node
*)nd
)->fcol
;
5161 const char *glyph_node::type()
5163 return "glyph_node";
5166 int glyph_node::force_tprint()
5171 int ligature_node::same(node
*nd
)
5173 return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
5174 && same_node(n2
, ((ligature_node
*)nd
)->n2
)
5175 && glyph_node::same(nd
));
5178 const char *ligature_node::type()
5180 return "ligature_node";
5183 int ligature_node::force_tprint()
5188 int kern_pair_node::same(node
*nd
)
5190 return (amount
== ((kern_pair_node
*)nd
)->amount
5191 && same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
5192 && same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
5195 const char *kern_pair_node::type()
5197 return "kern_pair_node";
5200 int kern_pair_node::force_tprint()
5205 int dbreak_node::same(node
*nd
)
5207 return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
5208 && same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
5209 && same_node_list(post
, ((dbreak_node
*)nd
)->post
));
5212 const char *dbreak_node::type()
5214 return "dbreak_node";
5217 int dbreak_node::force_tprint()
5222 int break_char_node::same(node
*nd
)
5224 return break_code
== ((break_char_node
*)nd
)->break_code
5225 && col
== ((break_char_node
*)nd
)->col
5226 && same_node(ch
, ((break_char_node
*)nd
)->ch
);
5229 const char *break_char_node::type()
5231 return "break_char_node";
5234 int break_char_node::force_tprint()
5239 int line_start_node::same(node
* /*nd*/)
5244 const char *line_start_node::type()
5246 return "line_start_node";
5249 int line_start_node::force_tprint()
5254 int space_node::same(node
*nd
)
5256 return n
== ((space_node
*)nd
)->n
5257 && set
== ((space_node
*)nd
)->set
5258 && col
== ((space_node
*)nd
)->col
;
5261 const char *space_node::type()
5263 return "space_node";
5266 int word_space_node::same(node
*nd
)
5268 return n
== ((word_space_node
*)nd
)->n
5269 && set
== ((word_space_node
*)nd
)->set
5270 && col
== ((word_space_node
*)nd
)->col
;
5273 const char *word_space_node::type()
5275 return "word_space_node";
5278 int word_space_node::force_tprint()
5283 void unbreakable_space_node::tprint(troff_output_file
*out
)
5285 out
->fill_color(col
);
5287 // we emit the space width as a negative glyph index
5291 out
->put(-n
.to_units());
5297 int unbreakable_space_node::same(node
*nd
)
5299 return n
== ((unbreakable_space_node
*)nd
)->n
5300 && set
== ((unbreakable_space_node
*)nd
)->set
5301 && col
== ((unbreakable_space_node
*)nd
)->col
;
5304 const char *unbreakable_space_node::type()
5306 return "unbreakable_space_node";
5309 node
*unbreakable_space_node::add_self(node
*n
, hyphen_list
**p
)
5312 hyphen_list
*pp
= *p
;
5318 hyphen_list
*unbreakable_space_node::get_hyphen_list(hyphen_list
*tail
, int *)
5320 return new hyphen_list(0, tail
);
5323 int diverted_space_node::same(node
*nd
)
5325 return n
== ((diverted_space_node
*)nd
)->n
;
5328 const char *diverted_space_node::type()
5330 return "diverted_space_node";
5333 int diverted_space_node::force_tprint()
5338 int diverted_copy_file_node::same(node
*nd
)
5340 return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
5343 const char *diverted_copy_file_node::type()
5345 return "diverted_copy_file_node";
5348 int diverted_copy_file_node::force_tprint()
5353 // Grow the font_table so that its size is > n.
5355 static void grow_font_table(int n
)
5357 assert(n
>= font_table_size
);
5358 font_info
**old_font_table
= font_table
;
5359 int old_font_table_size
= font_table_size
;
5360 font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
5361 if (font_table_size
<= n
)
5362 font_table_size
= n
+ 10;
5363 font_table
= new font_info
*[font_table_size
];
5364 if (old_font_table_size
)
5365 memcpy(font_table
, old_font_table
,
5366 old_font_table_size
*sizeof(font_info
*));
5367 a_delete old_font_table
;
5368 for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
5372 dictionary
font_translation_dictionary(17);
5374 static symbol
get_font_translation(symbol nm
)
5376 void *p
= font_translation_dictionary
.lookup(nm
);
5377 return p
? symbol((char *)p
) : nm
;
5380 dictionary
font_dictionary(50);
5382 static int mount_font_no_translate(int n
, symbol name
, symbol external_name
)
5385 // We store the address of this char in font_dictionary to indicate
5386 // that we've previously tried to mount the font and failed.
5389 void *p
= font_dictionary
.lookup(external_name
);
5392 fm
= font::load_font(external_name
.contents(), ¬_found
);
5395 warning(WARN_FONT
, "can't find font `%1'", external_name
.contents());
5396 (void)font_dictionary
.lookup(external_name
, &a_char
);
5399 (void)font_dictionary
.lookup(name
, fm
);
5401 else if (p
== &a_char
) {
5403 error("invalid font `%1'", external_name
.contents());
5409 if (n
>= font_table_size
) {
5410 if (n
- font_table_size
> 1000) {
5411 error("font position too much larger than first unused position");
5416 else if (font_table
[n
] != 0)
5417 delete font_table
[n
];
5418 font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
5419 font_family::invalidate_fontno(n
);
5423 int mount_font(int n
, symbol name
, symbol external_name
)
5426 name
= get_font_translation(name
);
5427 if (external_name
.is_null())
5428 external_name
= name
;
5430 external_name
= get_font_translation(external_name
);
5431 return mount_font_no_translate(n
, name
, external_name
);
5434 void mount_style(int n
, symbol name
)
5437 if (n
>= font_table_size
) {
5438 if (n
- font_table_size
> 1000) {
5439 error("font position too much larger than first unused position");
5444 else if (font_table
[n
] != 0)
5445 delete font_table
[n
];
5446 font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
5447 font_family::invalidate_fontno(n
);
5450 /* global functions */
5452 void font_translate()
5454 symbol from
= get_name(1);
5455 if (!from
.is_null()) {
5456 symbol to
= get_name();
5457 if (to
.is_null() || from
== to
)
5458 font_translation_dictionary
.remove(from
);
5460 (void)font_translation_dictionary
.lookup(from
, (void *)to
.contents());
5465 void font_position()
5468 if (get_integer(&n
)) {
5470 error("negative font position");
5472 symbol internal_name
= get_name(1);
5473 if (!internal_name
.is_null()) {
5474 symbol external_name
= get_long_name();
5475 mount_font(n
, internal_name
, external_name
); // ignore error
5482 font_family::font_family(symbol s
)
5483 : map_size(10), nm(s
)
5485 map
= new int[map_size
];
5486 for (int i
= 0; i
< map_size
; i
++)
5490 font_family::~font_family()
5495 int font_family::make_definite(int i
)
5498 if (i
< map_size
&& map
[i
] >= 0)
5501 if (i
< font_table_size
&& font_table
[i
] != 0) {
5502 if (i
>= map_size
) {
5503 int old_map_size
= map_size
;
5509 map
= new int[map_size
];
5510 memcpy(map
, old_map
, old_map_size
*sizeof(int));
5512 for (int j
= old_map_size
; j
< map_size
; j
++)
5515 if (font_table
[i
]->is_style()) {
5516 symbol sty
= font_table
[i
]->get_name();
5517 symbol f
= concat(nm
, sty
);
5519 // don't use symbol_fontno, because that might return a style
5520 // and because we don't want to translate the name
5521 for (n
= 0; n
< font_table_size
; n
++)
5522 if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
5523 && !font_table
[n
]->is_style())
5525 if (n
>= font_table_size
) {
5526 n
= next_available_font_position();
5527 if (!mount_font_no_translate(n
, f
, f
))
5543 dictionary
family_dictionary(5);
5545 font_family
*lookup_family(symbol nm
)
5547 font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
5549 f
= new font_family(nm
);
5550 (void)family_dictionary
.lookup(nm
, f
);
5555 void font_family::invalidate_fontno(int n
)
5557 assert(n
>= 0 && n
< font_table_size
);
5558 dictionary_iterator
iter(family_dictionary
);
5561 while (iter
.get(&nm
, (void **)&fam
)) {
5562 int map_size
= fam
->map_size
;
5565 for (int i
= 0; i
< map_size
; i
++)
5566 if (fam
->map
[i
] == n
)
5574 if (get_integer(&n
)) {
5576 error("negative font position");
5578 symbol internal_name
= get_name(1);
5579 if (!internal_name
.is_null())
5580 mount_style(n
, internal_name
);
5586 static int get_fontno()
5590 if (tok
.delimiter()) {
5591 symbol s
= get_name(1);
5593 n
= symbol_fontno(s
);
5595 n
= next_available_font_position();
5596 if (!mount_font(n
, s
))
5599 return curenv
->get_family()->make_definite(n
);
5602 else if (get_integer(&n
)) {
5603 if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
5604 error("bad font number");
5606 return curenv
->get_family()->make_definite(n
);
5611 static int underline_fontno
= 2;
5613 void underline_font()
5615 int n
= get_fontno();
5617 underline_fontno
= n
;
5621 int get_underline_fontno()
5623 return underline_fontno
;
5626 void define_font_special_character()
5628 int n
= get_fontno();
5633 symbol f
= font_table
[n
]->get_name();
5634 do_define_character(CHAR_FONT_SPECIAL
, f
.contents());
5637 void remove_font_special_character()
5639 int n
= get_fontno();
5644 symbol f
= font_table
[n
]->get_name();
5645 while (!tok
.newline() && !tok
.eof()) {
5646 if (!tok
.space() && !tok
.tab()) {
5647 charinfo
*s
= tok
.get_char(1);
5648 string
gl(f
.contents());
5650 gl
+= s
->nm
.contents();
5652 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
5655 macro
*m
= ci
->set_macro(0);
5664 static void read_special_fonts(special_font_list
**sp
)
5666 special_font_list
*s
= *sp
;
5669 special_font_list
*tem
= s
;
5673 special_font_list
**p
= sp
;
5675 int i
= get_fontno();
5677 special_font_list
*tem
= new special_font_list
;
5686 void font_special_request()
5688 int n
= get_fontno();
5690 read_special_fonts(&font_table
[n
]->sf
);
5694 void special_request()
5696 read_special_fonts(&global_special_fonts
);
5700 int next_available_font_position()
5703 for (i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
5708 int symbol_fontno(symbol s
)
5710 s
= get_font_translation(s
);
5711 for (int i
= 0; i
< font_table_size
; i
++)
5712 if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
5717 int is_good_fontno(int n
)
5719 return n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0;
5722 int get_bold_fontno(int n
)
5724 if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
5726 if (font_table
[n
]->get_bold(&offset
))
5727 return offset
.to_units() + 1;
5735 hunits
env_digit_width(environment
*env
)
5737 node
*n
= make_glyph_node(charset_table
['0'], env
);
5739 hunits x
= n
->width();
5747 hunits
env_space_width(environment
*env
)
5749 int fn
= env_definite_font(env
);
5750 font_size fs
= env
->get_font_size();
5751 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5752 return scale(fs
.to_units()/3, env
->get_space_size(), 12);
5754 return font_table
[fn
]->get_space_width(fs
, env
->get_space_size());
5757 hunits
env_sentence_space_width(environment
*env
)
5759 int fn
= env_definite_font(env
);
5760 font_size fs
= env
->get_font_size();
5761 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5762 return scale(fs
.to_units()/3, env
->get_sentence_space_size(), 12);
5764 return font_table
[fn
]->get_space_width(fs
, env
->get_sentence_space_size());
5767 hunits
env_half_narrow_space_width(environment
*env
)
5769 int fn
= env_definite_font(env
);
5770 font_size fs
= env
->get_font_size();
5771 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5774 return font_table
[fn
]->get_half_narrow_space_width(fs
);
5777 hunits
env_narrow_space_width(environment
*env
)
5779 int fn
= env_definite_font(env
);
5780 font_size fs
= env
->get_font_size();
5781 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
5784 return font_table
[fn
]->get_narrow_space_width(fs
);
5789 int n
= get_fontno();
5792 if (tok
.delimiter()) {
5793 int f
= get_fontno();
5796 if (has_arg() && get_number(&offset
, 'u') && offset
>= 1)
5797 font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
5799 font_table
[f
]->conditional_unbold(n
);
5804 if (get_number(&offset
, 'u') && offset
>= 1)
5805 font_table
[n
]->set_bold(hunits(offset
- 1));
5807 font_table
[n
]->unbold();
5811 font_table
[n
]->unbold();
5816 track_kerning_function::track_kerning_function() : non_zero(0)
5820 track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
5821 int max_s
, hunits max_a
)
5822 : non_zero(1), min_size(min_s
), min_amount(min_a
), max_size(max_s
),
5827 int track_kerning_function::operator==(const track_kerning_function
&tk
)
5831 && min_size
== tk
.min_size
5832 && min_amount
== tk
.min_amount
5833 && max_size
== tk
.max_size
5834 && max_amount
== tk
.max_amount
);
5836 return !tk
.non_zero
;
5839 int track_kerning_function::operator!=(const track_kerning_function
&tk
)
5842 return (!tk
.non_zero
5843 || min_size
!= tk
.min_size
5844 || min_amount
!= tk
.min_amount
5845 || max_size
!= tk
.max_size
5846 || max_amount
!= tk
.max_amount
);
5851 hunits
track_kerning_function::compute(int size
)
5854 if (max_size
<= min_size
)
5856 else if (size
<= min_size
)
5858 else if (size
>= max_size
)
5861 return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
5862 + scale(min_amount
, max_size
- size
, max_size
- min_size
));
5870 int n
= get_fontno();
5873 hunits min_a
, max_a
;
5875 && get_number(&min_s
, 'z')
5876 && get_hunits(&min_a
, 'p')
5877 && get_number(&max_s
, 'z')
5878 && get_hunits(&max_a
, 'p')) {
5879 track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
5880 font_table
[n
]->set_track_kern(tk
);
5883 track_kerning_function tk
;
5884 font_table
[n
]->set_track_kern(tk
);
5890 void constant_space()
5892 int n
= get_fontno();
5895 if (!has_arg() || !get_integer(&x
))
5896 font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
5898 if (!has_arg() || !get_number(&y
, 'z'))
5899 font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
5901 font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
5913 if (has_arg() && get_integer(&lig
) && lig
>= 0 && lig
<= 2)
5914 global_ligature_mode
= lig
;
5916 global_ligature_mode
= 1;
5923 if (has_arg() && get_integer(&k
))
5924 global_kern_mode
= k
!= 0;
5926 global_kern_mode
= 1;
5930 void set_soft_hyphen_char()
5932 soft_hyphen_char
= get_optional_char();
5933 if (!soft_hyphen_char
)
5934 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);
5940 if (suppress_output_flag
)
5941 the_output
= new suppress_output_file
;
5942 else if (ascii_output_flag
)
5943 the_output
= new ascii_output_file
;
5945 the_output
= new troff_output_file
;
5948 class next_available_font_position_reg
: public reg
{
5950 const char *get_string();
5953 const char *next_available_font_position_reg::get_string()
5955 return i_to_a(next_available_font_position());
5958 class printing_reg
: public reg
{
5960 const char *get_string();
5963 const char *printing_reg::get_string()
5966 return the_output
->is_printing() ? "1" : "0";
5971 void init_node_requests()
5973 init_request("bd", bold_font
);
5974 init_request("cs", constant_space
);
5975 init_request("fp", font_position
);
5976 init_request("fschar", define_font_special_character
);
5977 init_request("fspecial", font_special_request
);
5978 init_request("ftr", font_translate
);
5979 init_request("kern", kern_request
);
5980 init_request("lg", ligature
);
5981 init_request("rfschar", remove_font_special_character
);
5982 init_request("shc", set_soft_hyphen_char
);
5983 init_request("special", special_request
);
5984 init_request("sty", style
);
5985 init_request("tkf", track_kern
);
5986 init_request("uf", underline_font
);
5987 number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
5988 number_reg_dictionary
.define(".kern",
5989 new constant_int_reg(&global_kern_mode
));
5990 number_reg_dictionary
.define(".lg",
5991 new constant_int_reg(&global_ligature_mode
));
5992 number_reg_dictionary
.define(".P", new printing_reg
);
5993 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);