2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 1992, 2000 - 2006, 2008 Free Software Foundation, Inc.
5 * Written by James Clark (jjc@jclark.com)
7 * This is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2, or (at your option) any later
12 * This is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * You should have received a copy of the GNU General Public License along
18 * with groff; see the file COPYING. If not, write to the Free Software
19 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
23 #include "troff-config.h"
29 #include "file_case.h"
33 #include "stringclass.h"
36 #include "dictionary.h"
48 extern int debug_state
;
49 // declarations to avoid friend name injections
52 tfont
*make_tfont(tfont_spec
&);
54 // how many boundaries of images have been written? Useful for
57 static int suppress_start_page
= 0;
61 symbol
HYPHEN_SYMBOL("hy");
63 // Character used when a hyphen is inserted at a line break.
64 static charinfo
*soft_hyphen_char
;
66 enum constant_space_type
{
68 CONSTANT_SPACE_RELATIVE
,
69 CONSTANT_SPACE_ABSOLUTE
72 struct special_font_list
{
74 special_font_list
*next
;
77 special_font_list
*global_special_fonts
;
78 static int global_ligature_mode
= 1;
79 static int global_kern_mode
= 1;
81 class track_kerning_function
90 track_kerning_function();
91 track_kerning_function(units
, hunits
, units
, hunits
);
92 int operator==(const track_kerning_function
&);
93 int operator!=(const track_kerning_function
&);
94 hunits
compute(int point_size
);
97 // embolden fontno when this is the current font
98 class conditional_bold
101 conditional_bold
*next
;
105 conditional_bold(int, hunits
, conditional_bold
* = 0);
115 symbol internal_name
;
116 symbol external_name
;
120 track_kerning_function track_kern
;
121 constant_space_type is_constant_spaced
;
122 units constant_space
;
123 int last_ligature_mode
;
125 conditional_bold
*cond_bold_list
;
130 special_font_list
*sf
;
132 font_info(symbol
, int, symbol
, font
*);
133 int contains(charinfo
*);
134 void set_bold(hunits
);
136 void set_conditional_bold(int, hunits
);
137 void conditional_unbold(int);
138 void set_track_kern(track_kerning_function
&);
139 void set_constant_space(constant_space_type
, units
= 0);
140 int is_named(symbol
);
142 tfont
*get_tfont(font_size
, int, int, int);
143 hunits
get_space_width(font_size
, int);
144 hunits
get_narrow_space_width(font_size
);
145 hunits
get_half_narrow_space_width(font_size
);
146 int get_bold(hunits
*);
151 friend symbol
get_font_name(int, environment
*);
152 friend symbol
get_style_name(int);
163 char is_constant_spaced
;
167 hunits track_kern
; // add this to the width
168 hunits constant_space_width
;
173 tfont_spec(symbol
, int, 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);
183 static tfont
*tfont_list
;
186 tfont
*plain_version
;
190 int contains(charinfo
*);
191 hunits
get_width(charinfo
*c
);
192 int get_bold(hunits
*);
193 int get_constant_space(hunits
*);
194 hunits
get_track_kern();
196 font_size
get_size();
199 charinfo
*get_lig(charinfo
*c1
, charinfo
*c2
);
200 int get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
);
201 int get_input_position();
202 int get_character_type(charinfo
*);
205 vunits
get_char_height(charinfo
*);
206 vunits
get_char_depth(charinfo
*);
207 hunits
get_char_skew(charinfo
*);
208 hunits
get_italic_correction(charinfo
*);
209 hunits
get_left_italic_correction(charinfo
*);
210 hunits
get_subscript_correction(charinfo
*);
211 friend tfont
*make_tfont(tfont_spec
&);
214 inline int env_definite_font(environment
*env
)
216 return env
->get_family()->make_definite(env
->get_font());
219 /* font_info functions */
221 static font_info
**font_table
= 0;
222 static int font_table_size
= 0;
224 font_info::font_info(symbol nm
, int n
, symbol enm
, font
*f
)
225 : last_tfont(0), number(n
), last_size(0),
226 internal_name(nm
), external_name(enm
), fm(f
),
227 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE
), last_ligature_mode(1),
228 last_kern_mode(1), cond_bold_list(0), sf(0)
232 inline int font_info::contains(charinfo
*ci
)
234 return fm
!= 0 && fm
->contains(ci
->as_glyph());
237 inline int font_info::is_special()
239 return fm
!= 0 && fm
->is_special();
242 inline int font_info::is_style()
247 void font_info::set_zoom(int zoom
)
253 inline int font_info::get_zoom()
257 return fm
->get_zoom();
260 tfont
*make_tfont(tfont_spec
&spec
)
262 for (tfont
*p
= tfont::tfont_list
; p
; p
= p
->next
)
265 return new tfont(spec
);
268 int env_get_zoom(environment
*env
)
270 int fontno
= env
->get_family()->make_definite(env
->get_font());
271 return font_table
[fontno
]->get_zoom();
274 // this is the current_font, fontno is where we found the character,
275 // presumably a special font
277 tfont
*font_info::get_tfont(font_size fs
, int height
, int slant
, int fontno
)
279 if (last_tfont
== 0 || fs
!= last_size
280 || height
!= last_height
|| slant
!= last_slant
281 || global_ligature_mode
!= last_ligature_mode
282 || global_kern_mode
!= last_kern_mode
283 || fontno
!= number
) {
284 font_info
*f
= font_table
[fontno
];
285 tfont_spec
spec(f
->external_name
, f
->number
, f
->fm
, fs
, height
, slant
);
286 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
287 if (p
->fontno
== fontno
) {
289 spec
.bold_offset
= p
->offset
;
292 if (!spec
.is_bold
&& is_bold
) {
294 spec
.bold_offset
= bold_offset
;
296 spec
.track_kern
= track_kern
.compute(fs
.to_scaled_points());
297 spec
.ligature_mode
= global_ligature_mode
;
298 spec
.kern_mode
= global_kern_mode
;
299 switch (is_constant_spaced
) {
300 case CONSTANT_SPACE_NONE
:
302 case CONSTANT_SPACE_ABSOLUTE
:
303 spec
.is_constant_spaced
= 1;
304 spec
.constant_space_width
= constant_space
;
306 case CONSTANT_SPACE_RELATIVE
:
307 spec
.is_constant_spaced
= 1;
308 spec
.constant_space_width
309 = scale(constant_space
*fs
.to_scaled_points(),
316 if (fontno
!= number
)
317 return make_tfont(spec
);
318 // save font for comparison purposes
319 last_tfont
= make_tfont(spec
);
320 // save font related values not contained in tfont
322 last_height
= height
;
324 last_ligature_mode
= global_ligature_mode
;
325 last_kern_mode
= global_kern_mode
;
330 int font_info::get_bold(hunits
*res
)
340 void font_info::unbold()
348 void font_info::set_bold(hunits offset
)
350 if (!is_bold
|| offset
!= bold_offset
) {
352 bold_offset
= offset
;
357 void font_info::set_conditional_bold(int fontno
, hunits offset
)
359 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
360 if (p
->fontno
== fontno
) {
361 if (offset
!= p
->offset
) {
367 cond_bold_list
= new conditional_bold(fontno
, offset
, cond_bold_list
);
370 conditional_bold::conditional_bold(int f
, hunits h
, conditional_bold
*x
)
371 : next(x
), fontno(f
), offset(h
)
375 void font_info::conditional_unbold(int fontno
)
377 for (conditional_bold
**p
= &cond_bold_list
; *p
; p
= &(*p
)->next
)
378 if ((*p
)->fontno
== fontno
) {
379 conditional_bold
*tem
= *p
;
387 void font_info::set_constant_space(constant_space_type type
, units x
)
389 if (type
!= is_constant_spaced
390 || (type
!= CONSTANT_SPACE_NONE
&& x
!= constant_space
)) {
392 is_constant_spaced
= type
;
397 void font_info::set_track_kern(track_kerning_function
&tk
)
399 if (track_kern
!= tk
) {
405 void font_info::flush()
410 int font_info::is_named(symbol s
)
412 return internal_name
== s
;
415 symbol
font_info::get_name()
417 return internal_name
;
420 symbol
get_font_name(int fontno
, environment
*env
)
422 symbol f
= font_table
[fontno
]->get_name();
423 if (font_table
[fontno
]->is_style()) {
424 return concat(env
->get_family()->nm
, f
);
429 symbol
get_style_name(int fontno
)
431 if (font_table
[fontno
]->is_style())
432 return font_table
[fontno
]->get_name();
437 hunits
font_info::get_space_width(font_size fs
, int space_sz
)
439 if (is_constant_spaced
== CONSTANT_SPACE_NONE
)
440 return scale(hunits(fm
->get_space_width(fs
.to_scaled_points())),
442 else if (is_constant_spaced
== CONSTANT_SPACE_ABSOLUTE
)
443 return constant_space
;
445 return scale(constant_space
*fs
.to_scaled_points(),
446 units_per_inch
, 36*72*sizescale
);
449 hunits
font_info::get_narrow_space_width(font_size fs
)
451 charinfo
*ci
= get_charinfo(symbol("|"));
452 if (fm
->contains(ci
->as_glyph()))
453 return hunits(fm
->get_width(ci
->as_glyph(), fs
.to_scaled_points()));
455 return hunits(fs
.to_units()/6);
458 hunits
font_info::get_half_narrow_space_width(font_size fs
)
460 charinfo
*ci
= get_charinfo(symbol("^"));
461 if (fm
->contains(ci
->as_glyph()))
462 return hunits(fm
->get_width(ci
->as_glyph(), fs
.to_scaled_points()));
464 return hunits(fs
.to_units()/12);
469 tfont_spec::tfont_spec(symbol nm
, int n
, font
*f
,
470 font_size s
, int h
, int sl
)
471 : name(nm
), input_position(n
), fm(f
), size(s
),
472 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
475 if (height
== size
.to_scaled_points())
479 int tfont_spec::operator==(const tfont_spec
&spec
)
483 && input_position
== spec
.input_position
485 && height
== spec
.height
486 && slant
== spec
.slant
488 ? (spec
.is_bold
&& bold_offset
== spec
.bold_offset
)
490 && track_kern
== spec
.track_kern
491 && (is_constant_spaced
492 ? (spec
.is_constant_spaced
493 && constant_space_width
== spec
.constant_space_width
)
494 : !spec
.is_constant_spaced
)
495 && ligature_mode
== spec
.ligature_mode
496 && kern_mode
== spec
.kern_mode
)
502 tfont_spec
tfont_spec::plain()
504 return tfont_spec(name
, input_position
, fm
, size
, height
, slant
);
507 hunits
tfont::get_width(charinfo
*c
)
509 if (is_constant_spaced
)
510 return constant_space_width
;
512 return (hunits(fm
->get_width(c
->as_glyph(), size
.to_scaled_points()))
513 + track_kern
+ bold_offset
);
515 return (hunits(fm
->get_width(c
->as_glyph(), size
.to_scaled_points()))
519 vunits
tfont::get_char_height(charinfo
*c
)
521 vunits v
= fm
->get_height(c
->as_glyph(), size
.to_scaled_points());
522 if (height
!= 0 && height
!= size
.to_scaled_points())
523 return scale(v
, height
, size
.to_scaled_points());
528 vunits
tfont::get_char_depth(charinfo
*c
)
530 vunits v
= fm
->get_depth(c
->as_glyph(), size
.to_scaled_points());
531 if (height
!= 0 && height
!= size
.to_scaled_points())
532 return scale(v
, height
, size
.to_scaled_points());
537 hunits
tfont::get_char_skew(charinfo
*c
)
539 return hunits(fm
->get_skew(c
->as_glyph(), size
.to_scaled_points(), slant
));
542 hunits
tfont::get_italic_correction(charinfo
*c
)
544 return hunits(fm
->get_italic_correction(c
->as_glyph(), size
.to_scaled_points()));
547 hunits
tfont::get_left_italic_correction(charinfo
*c
)
549 return hunits(fm
->get_left_italic_correction(c
->as_glyph(),
550 size
.to_scaled_points()));
553 hunits
tfont::get_subscript_correction(charinfo
*c
)
555 return hunits(fm
->get_subscript_correction(c
->as_glyph(),
556 size
.to_scaled_points()));
559 inline int tfont::get_input_position()
561 return input_position
;
564 inline int tfont::contains(charinfo
*ci
)
566 return fm
->contains(ci
->as_glyph());
569 inline int tfont::get_character_type(charinfo
*ci
)
571 return fm
->get_character_type(ci
->as_glyph());
574 inline int tfont::get_bold(hunits
*res
)
584 inline int tfont::get_constant_space(hunits
*res
)
586 if (is_constant_spaced
) {
587 *res
= constant_space_width
;
594 inline hunits
tfont::get_track_kern()
599 inline tfont
*tfont::get_plain()
601 return plain_version
;
604 inline font_size
tfont::get_size()
609 inline int tfont::get_zoom()
611 return fm
->get_zoom();
614 inline symbol
tfont::get_name()
619 inline int tfont::get_height()
624 inline int tfont::get_slant()
629 symbol
SYMBOL_ff("ff");
630 symbol
SYMBOL_fi("fi");
631 symbol
SYMBOL_fl("fl");
632 symbol
SYMBOL_Fi("Fi");
633 symbol
SYMBOL_Fl("Fl");
635 charinfo
*tfont::get_lig(charinfo
*c1
, charinfo
*c2
)
637 if (ligature_mode
== 0)
640 if (c1
->get_ascii_code() == 'f') {
641 switch (c2
->get_ascii_code()) {
643 if (fm
->has_ligature(font::LIG_ff
))
644 ci
= get_charinfo(SYMBOL_ff
);
647 if (fm
->has_ligature(font::LIG_fi
))
648 ci
= get_charinfo(SYMBOL_fi
);
651 if (fm
->has_ligature(font::LIG_fl
))
652 ci
= get_charinfo(SYMBOL_fl
);
656 else if (ligature_mode
!= 2 && c1
->nm
== SYMBOL_ff
) {
657 switch (c2
->get_ascii_code()) {
659 if (fm
->has_ligature(font::LIG_ffi
))
660 ci
= get_charinfo(SYMBOL_Fi
);
663 if (fm
->has_ligature(font::LIG_ffl
))
664 ci
= get_charinfo(SYMBOL_Fl
);
668 if (ci
!= 0 && fm
->contains(ci
->as_glyph()))
673 inline int tfont::get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
)
678 int n
= fm
->get_kern(c1
->as_glyph(),
680 size
.to_scaled_points());
690 tfont
*tfont::tfont_list
= 0;
692 tfont::tfont(tfont_spec
&spec
) : tfont_spec(spec
)
696 tfont_spec plain_spec
= plain();
698 for (p
= tfont_list
; p
; p
= p
->next
)
699 if (*p
== plain_spec
) {
704 plain_version
= new tfont(plain_spec
);
709 class real_output_file
712 #ifndef POPEN_MISSING
715 int printing
; // decision via optional page list
716 int output_on
; // \O[0] or \O[1] escape calls
718 virtual void really_transparent_char(unsigned char) = 0;
719 virtual void really_print_line(hunits x
, vunits y
, node
*n
,
720 vunits before
, vunits after
, hunits width
) = 0;
721 virtual void really_begin_page(int pageno
, vunits page_length
) = 0;
722 virtual void really_copy_file(hunits x
, vunits y
, const char *filename
);
723 virtual void really_put_filename(const char *, int);
724 virtual void really_on();
725 virtual void really_off();
733 void transparent_char(unsigned char);
734 void print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
735 void begin_page(int pageno
, vunits page_length
);
736 void put_filename(const char *, int);
741 void copy_file(hunits x
, vunits y
, const char *filename
);
744 class suppress_output_file
745 : public real_output_file
748 suppress_output_file();
749 void really_transparent_char(unsigned char);
750 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
751 void really_begin_page(int pageno
, vunits page_length
);
754 class ascii_output_file
755 : public real_output_file
759 void really_transparent_char(unsigned char);
760 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
, hunits width
);
761 void really_begin_page(int pageno
, vunits page_length
);
762 void outc(unsigned char c
);
763 void outs(const char *s
);
766 void ascii_output_file::outc(unsigned char c
)
771 void ascii_output_file::outs(const char *s
)
781 class troff_output_file
782 : public real_output_file
784 friend void space_char_hmotion_node::tprint(troff_output_file
*);
785 friend void unbreakable_space_node::tprint(troff_output_file
*);
795 tfont
*current_tfont
;
796 color
*current_fill_color
;
797 color
*current_glyph_color
;
798 int current_font_number
;
799 symbol
*font_position
;
801 enum { TBUF_SIZE
= 256 };
802 char tbuf
[TBUF_SIZE
];
811 void put(unsigned char c
);
813 void put(unsigned int i
);
814 void put(const char *s
);
815 void set_font(tfont
*tf
);
820 ~troff_output_file();
821 void trailer(vunits page_length
);
822 void put_char(charinfo
*, tfont
*, color
*, color
*);
823 void put_char_width(charinfo
*, tfont
*, color
*, color
*, hunits
, hunits
);
826 void moveto(hunits
, vunits
);
827 void start_special(tfont
*, color
*, color
*, int = 0);
828 void start_special();
829 void special_char(unsigned char c
);
832 void really_transparent_char(unsigned char c
);
833 void really_print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
, hunits width
);
834 void really_begin_page(int pageno
, vunits page_length
);
835 void really_copy_file(hunits x
, vunits y
, const char *filename
);
836 void really_put_filename(const char *, int);
839 void draw(char, hvpair
*, int, font_size
, color
*, color
*);
840 void determine_line_limits (char code
, hvpair
*point
, int npoints
);
841 void check_charinfo(tfont
*tf
, charinfo
*ci
);
842 void glyph_color(color
*c
);
843 void fill_color(color
*c
);
844 int get_hpos() { return hpos
; }
845 int get_vpos() { return vpos
; }
846 void add_to_tag_list(string s
);
849 static void put_string(const char *s
, FILE *fp
)
851 for (; *s
!= '\0'; ++s
)
855 inline void troff_output_file::put(char c
)
860 inline void troff_output_file::put(unsigned char c
)
865 inline void troff_output_file::put(const char *s
)
870 inline void troff_output_file::put(int i
)
872 put_string(i_to_a(i
), fp
);
875 inline void troff_output_file::put(unsigned int i
)
877 put_string(ui_to_a(i
), fp
);
880 void troff_output_file::start_special(tfont
*tf
, color
*gcol
, color
*fcol
,
892 void troff_output_file::start_special()
899 void troff_output_file::special_char(unsigned char c
)
906 void troff_output_file::end_special()
911 inline void troff_output_file::moveto(hunits h
, vunits v
)
917 void troff_output_file::really_print_line(hunits x
, vunits y
, node
*n
,
918 vunits before
, vunits after
, hunits
)
922 // Check whether we should push the current troff state and use
923 // the state at the start of the invocation of this diversion.
924 if (n
->div_nest_level
> cur_div_level
&& n
->push_state
) {
925 state
.push_state(n
->push_state
);
926 cur_div_level
= n
->div_nest_level
;
928 // Has the current diversion level decreased? Then we must pop the
930 while (n
->div_nest_level
< cur_div_level
) {
932 cur_div_level
= n
->div_nest_level
;
934 // Now check whether the state has changed.
935 if ((is_on() || n
->force_tprint())
936 && (state
.changed(n
->state
) || n
->is_tag() || n
->is_special
)) {
941 state
.flush(fp
, n
->state
, tag_list
);
942 tag_list
= string("");
949 // This ensures that transparent throughput will have a more predictable
955 put(before
.to_units());
957 put(after
.to_units());
961 inline void troff_output_file::word_marker()
968 inline void troff_output_file::right(hunits n
)
970 hpos
+= n
.to_units();
973 inline void troff_output_file::down(vunits n
)
975 vpos
+= n
.to_units();
978 void troff_output_file::do_motion()
989 if (hpos
!= output_hpos
) {
990 units n
= hpos
- output_hpos
;
991 if (n
> 0 && n
< hpos
) {
1001 if (vpos
!= output_vpos
) {
1002 units n
= vpos
- output_vpos
;
1003 if (n
> 0 && n
< vpos
) {
1019 void troff_output_file::flush_tbuf()
1035 check_output_limits(hpos
, vpos
);
1036 check_output_limits(hpos
, vpos
- current_size
);
1038 for (int i
= 0; i
< tbuf_len
; i
++)
1044 void troff_output_file::check_charinfo(tfont
*tf
, charinfo
*ci
)
1049 int height
= tf
->get_char_height(ci
).to_units();
1050 int width
= tf
->get_width(ci
).to_units()
1051 + tf
->get_italic_correction(ci
).to_units();
1052 int depth
= tf
->get_char_depth(ci
).to_units();
1053 check_output_limits(output_hpos
, output_vpos
- height
);
1054 check_output_limits(output_hpos
+ width
, output_vpos
+ depth
);
1057 void troff_output_file::put_char_width(charinfo
*ci
, tfont
*tf
,
1058 color
*gcol
, color
*fcol
,
1061 int kk
= k
.to_units();
1064 hpos
+= w
.to_units() + kk
;
1068 unsigned char c
= ci
->get_ascii_code();
1074 check_charinfo(tf
, ci
);
1075 if (ci
->numbered()) {
1077 put(ci
->get_number());
1081 const char *s
= ci
->nm
.contents();
1090 hpos
+= w
.to_units() + kk
;
1092 else if (tcommand_flag
) {
1093 if (tbuf_len
> 0 && hpos
== output_hpos
&& vpos
== output_vpos
1094 && (!gcol
|| gcol
== current_glyph_color
)
1095 && (!fcol
|| fcol
== current_fill_color
)
1097 && tbuf_len
< TBUF_SIZE
) {
1098 check_charinfo(tf
, ci
);
1099 tbuf
[tbuf_len
++] = c
;
1100 output_hpos
+= w
.to_units() + kk
;
1108 check_charinfo(tf
, ci
);
1109 tbuf
[tbuf_len
++] = c
;
1110 output_hpos
+= w
.to_units() + kk
;
1116 int n
= hpos
- output_hpos
;
1117 check_charinfo(tf
, ci
);
1118 // check_output_limits(output_hpos, output_vpos);
1119 if (vpos
== output_vpos
1120 && (!gcol
|| gcol
== current_glyph_color
)
1121 && (!fcol
|| fcol
== current_fill_color
)
1122 && n
> 0 && n
< 100 && !force_motion
) {
1123 put(char(n
/10 + '0'));
1124 put(char(n
%10 + '0'));
1135 hpos
+= w
.to_units() + kk
;
1139 void troff_output_file::put_char(charinfo
*ci
, tfont
*tf
,
1140 color
*gcol
, color
*fcol
)
1146 unsigned char c
= ci
->get_ascii_code();
1152 if (ci
->numbered()) {
1154 put(ci
->get_number());
1158 const char *s
= ci
->nm
.contents();
1169 int n
= hpos
- output_hpos
;
1170 if (vpos
== output_vpos
1171 && (!gcol
|| gcol
== current_glyph_color
)
1172 && (!fcol
|| fcol
== current_fill_color
)
1173 && n
> 0 && n
< 100) {
1174 put(char(n
/10 + '0'));
1175 put(char(n
%10 + '0'));
1190 // set_font calls `flush_tbuf' if necessary.
1192 void troff_output_file::set_font(tfont
*tf
)
1194 if (current_tfont
== tf
)
1197 int n
= tf
->get_input_position();
1198 symbol nm
= tf
->get_name();
1199 if (n
>= nfont_positions
|| font_position
[n
] != nm
) {
1205 if (n
>= nfont_positions
) {
1206 int old_nfont_positions
= nfont_positions
;
1207 symbol
*old_font_position
= font_position
;
1208 nfont_positions
*= 3;
1209 nfont_positions
/= 2;
1210 if (nfont_positions
<= n
)
1211 nfont_positions
= n
+ 10;
1212 font_position
= new symbol
[nfont_positions
];
1213 memcpy(font_position
, old_font_position
,
1214 old_nfont_positions
*sizeof(symbol
));
1215 a_delete old_font_position
;
1217 font_position
[n
] = nm
;
1219 if (current_font_number
!= n
) {
1223 current_font_number
= n
;
1225 int zoom
= tf
->get_zoom();
1228 size
= scale(tf
->get_size().to_scaled_points(),
1231 size
= tf
->get_size().to_scaled_points();
1232 if (current_size
!= size
) {
1236 current_size
= size
;
1238 int slant
= tf
->get_slant();
1239 if (current_slant
!= slant
) {
1243 current_slant
= slant
;
1245 int height
= tf
->get_height();
1246 if (current_height
!= height
) {
1248 put(height
== 0 ? current_size
: height
);
1250 current_height
= height
;
1255 // fill_color calls `flush_tbuf' and `do_motion' if necessary.
1257 void troff_output_file::fill_color(color
*col
)
1259 if (!col
|| current_fill_color
== col
)
1261 current_fill_color
= col
;
1267 unsigned int components
[4];
1269 cs
= col
->get_components(components
);
1308 // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1310 void troff_output_file::glyph_color(color
*col
)
1312 if (!col
|| current_glyph_color
== col
)
1314 current_glyph_color
= col
;
1318 // grotty doesn't like a color command if the vertical position is zero.
1321 unsigned int components
[4];
1323 cs
= col
->get_components(components
);
1362 void troff_output_file::add_to_tag_list(string s
)
1364 if (tag_list
== string(""))
1367 tag_list
+= string("\n");
1372 // determine_line_limits - works out the smallest box which will contain
1373 // the entity, code, built from the point array.
1374 void troff_output_file::determine_line_limits(char code
, hvpair
*point
,
1385 // only the h field is used when defining a circle
1386 check_output_limits(output_hpos
,
1387 output_vpos
- point
[0].h
.to_units()/2);
1388 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1389 output_vpos
+ point
[0].h
.to_units()/2);
1393 check_output_limits(output_hpos
,
1394 output_vpos
- point
[0].v
.to_units()/2);
1395 check_output_limits(output_hpos
+ point
[0].h
.to_units(),
1396 output_vpos
+ point
[0].v
.to_units()/2);
1402 check_output_limits(x
, y
);
1403 for (i
= 0; i
< npoints
; i
++) {
1404 x
+= point
[i
].h
.to_units();
1405 y
+= point
[i
].v
.to_units();
1406 check_output_limits(x
, y
);
1412 for (i
= 0; i
< npoints
; i
++) {
1413 x
+= point
[i
].h
.to_units();
1414 y
+= point
[i
].v
.to_units();
1415 check_output_limits(x
, y
);
1421 int minx
, miny
, maxx
, maxy
;
1424 p
[0] = point
[0].h
.to_units();
1425 p
[1] = point
[0].v
.to_units();
1426 p
[2] = point
[1].h
.to_units();
1427 p
[3] = point
[1].v
.to_units();
1428 if (adjust_arc_center(p
, c
)) {
1429 check_output_arc_limits(x
, y
,
1430 p
[0], p
[1], p
[2], p
[3],
1432 &minx
, &maxx
, &miny
, &maxy
);
1433 check_output_limits(minx
, miny
);
1434 check_output_limits(maxx
, maxy
);
1441 check_output_limits(x
, y
);
1442 for (i
= 0; i
< npoints
; i
++) {
1443 x
+= point
[i
].h
.to_units();
1444 y
+= point
[i
].v
.to_units();
1445 check_output_limits(x
, y
);
1451 for (i
= 0; i
< npoints
; i
++) {
1452 x
+= point
[i
].h
.to_units();
1453 y
+= point
[i
].v
.to_units();
1454 check_output_limits(x
, y
);
1459 void troff_output_file::draw(char code
, hvpair
*point
, int npoints
,
1460 font_size fsize
, color
*gcol
, color
*fcol
)
1468 int size
= fsize
.to_scaled_points();
1469 if (current_size
!= size
) {
1473 current_size
= size
;
1480 put(point
[0].h
.to_units());
1483 for (i
= 0; i
< npoints
; i
++) {
1485 put(point
[i
].h
.to_units());
1487 put(point
[i
].v
.to_units());
1489 determine_line_limits(code
, point
, npoints
);
1492 for (i
= 0; i
< npoints
; i
++)
1493 output_hpos
+= point
[i
].h
.to_units();
1496 for (i
= 0; i
< npoints
; i
++)
1497 output_vpos
+= point
[i
].v
.to_units();
1504 void troff_output_file::really_on()
1511 void troff_output_file::really_off()
1516 void troff_output_file::really_put_filename(const char *filename
, int po
)
1528 void troff_output_file::really_begin_page(int pageno
, vunits page_length
)
1532 if (page_length
> V0
) {
1534 put(page_length
.to_units());
1541 current_font_number
= -1;
1543 // current_height = 0;
1544 // current_slant = 0;
1550 for (int i
= 0; i
< nfont_positions
; i
++)
1551 font_position
[i
] = NULL_SYMBOL
;
1557 void troff_output_file::really_copy_file(hunits x
, vunits y
,
1558 const char *filename
)
1564 file_case
*fcp
= include_search_path
.open_file_cautious(filename
,
1565 fcp
->fc_const_path
);
1568 while ((c
= fcp
->get_c()) != EOF
)
1572 error("can't open `%1': %2", filename
, strerror(errno
));
1577 current_font_number
= -1;
1578 for (int i
= 0; i
< nfont_positions
; i
++)
1579 font_position
[i
] = NULL_SYMBOL
;
1582 void troff_output_file::really_transparent_char(unsigned char c
)
1587 troff_output_file::~troff_output_file()
1589 a_delete font_position
;
1592 void troff_output_file::trailer(vunits page_length
)
1595 if (page_length
> V0
) {
1598 put(page_length
.to_units());
1604 troff_output_file::troff_output_file()
1605 : current_slant(0), current_height(0), current_fill_color(0),
1606 current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0),
1609 font_position
= new symbol
[nfont_positions
];
1614 put(units_per_inch
);
1625 output_file
*the_output
= 0;
1627 output_file::output_file()
1631 output_file::~output_file()
1635 void output_file::trailer(vunits
)
1639 void output_file::put_filename(const char *, int)
1643 void output_file::on()
1647 void output_file::off()
1651 real_output_file::real_output_file()
1652 : printing(0), output_on(1)
1654 #ifndef POPEN_MISSING
1656 if ((fp
= popen(pipe_command
, POPEN_WT
)) != 0) {
1660 error("pipe open failed: %1", strerror(errno
));
1663 #endif /* not POPEN_MISSING */
1667 real_output_file::~real_output_file()
1671 // To avoid looping, set fp to 0 before calling fatal().
1672 if (ferror(fp
) || fflush(fp
) < 0) {
1674 fatal("error writing output file");
1676 #ifndef POPEN_MISSING
1678 int result
= pclose(fp
);
1681 fatal("pclose failed");
1682 if (!WIFEXITED(result
))
1683 error("output process `%1' got fatal signal %2",
1685 WIFSIGNALED(result
) ? WTERMSIG(result
) : WSTOPSIG(result
));
1687 int exit_status
= WEXITSTATUS(result
);
1688 if (exit_status
!= 0)
1689 error("output process `%1' exited with status %2",
1690 pipe_command
, exit_status
);
1694 #endif /* not POPEN MISSING */
1695 if (fclose(fp
) < 0) {
1697 fatal("error closing output file");
1701 void real_output_file::flush()
1704 fatal("error writing output file");
1707 int real_output_file::is_printing()
1712 void real_output_file::begin_page(int pageno
, vunits page_length
)
1714 printing
= in_output_page_list(pageno
);
1716 really_begin_page(pageno
, page_length
);
1719 void real_output_file::copy_file(hunits x
, vunits y
, const char *filename
)
1721 if (printing
&& output_on
)
1722 really_copy_file(x
, y
, filename
);
1723 check_output_limits(x
.to_units(), y
.to_units());
1726 void real_output_file::transparent_char(unsigned char c
)
1728 if (printing
&& output_on
)
1729 really_transparent_char(c
);
1732 void real_output_file::print_line(hunits x
, vunits y
, node
*n
,
1733 vunits before
, vunits after
, hunits width
)
1736 really_print_line(x
, y
, n
, before
, after
, width
);
1737 delete_node_list(n
);
1740 void real_output_file::really_copy_file(hunits
, vunits
, const char *)
1745 void real_output_file::put_filename(const char *filename
, int po
)
1747 really_put_filename(filename
, po
);
1750 void real_output_file::really_put_filename(const char *, int)
1754 void real_output_file::on()
1761 void real_output_file::off()
1767 int real_output_file::is_on()
1772 void real_output_file::really_on()
1776 void real_output_file::really_off()
1780 /* ascii_output_file */
1782 void ascii_output_file::really_transparent_char(unsigned char c
)
1787 void ascii_output_file::really_print_line(hunits
, vunits
, node
*n
,
1788 vunits
, vunits
, hunits
)
1791 n
->ascii_print(this);
1797 void ascii_output_file::really_begin_page(int /*pageno*/, vunits
/*page_length*/)
1799 fputs("<beginning of page>\n", fp
);
1802 ascii_output_file::ascii_output_file()
1806 /* suppress_output_file */
1808 suppress_output_file::suppress_output_file()
1812 void suppress_output_file::really_print_line(hunits
, vunits
, node
*, vunits
, vunits
, hunits
)
1816 void suppress_output_file::really_begin_page(int, vunits
)
1820 void suppress_output_file::really_transparent_char(unsigned char)
1824 /* glyphs, ligatures, kerns, discretionary breaks */
1833 charinfo_node(charinfo
*, statem
*, int, node
* = 0);
1834 int ends_sentence();
1835 int overlaps_vertically();
1836 int overlaps_horizontally();
1839 charinfo_node::charinfo_node(charinfo
*c
, statem
*s
, int pop
, node
*x
)
1840 : node(x
, s
, pop
), ci(c
)
1844 int charinfo_node::ends_sentence()
1846 if (ci
->ends_sentence())
1848 else if (ci
->transparent())
1854 int charinfo_node::overlaps_horizontally()
1856 return ci
->overlaps_horizontally();
1859 int charinfo_node::overlaps_vertically()
1861 return ci
->overlaps_vertically();
1865 : public charinfo_node
1867 static glyph_node
*free_list
;
1872 color
*fcol
; /* this is needed for grotty */
1876 glyph_node(charinfo
*, tfont
*, color
*, color
*, hunits
,
1877 statem
*, int, node
* = 0);
1881 void *operator new(size_t);
1882 void operator delete(void *);
1883 glyph_node(charinfo
*, tfont
*, color
*, color
*,
1884 statem
*, int, node
* = 0);
1887 node
*merge_glyph_node(glyph_node
*);
1888 node
*merge_self(node
*);
1890 node
*last_char_node();
1892 void vertical_extent(vunits
*, vunits
*);
1893 hunits
subscript_correction();
1894 hunits
italic_correction();
1895 hunits
left_italic_correction();
1897 hyphenation_type
get_hyphenation_type();
1899 color
*get_glyph_color();
1900 color
*get_fill_color();
1901 void tprint(troff_output_file
*);
1902 void zero_width_tprint(troff_output_file
*);
1903 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1904 node
*add_self(node
*, hyphen_list
**);
1905 void ascii_print(ascii_output_file
*);
1906 void asciify(macro
*);
1907 int character_type();
1915 glyph_node
*glyph_node::free_list
= 0;
1924 ligature_node(charinfo
*, tfont
*, color
*, color
*, hunits
,
1925 node
*, node
*, statem
*, int, node
* = 0);
1929 void *operator new(size_t);
1930 void operator delete(void *);
1931 ligature_node(charinfo
*, tfont
*, color
*, color
*,
1932 node
*, node
*, statem
*, int, node
* = 0);
1935 node
*add_self(node
*, hyphen_list
**);
1936 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1937 void ascii_print(ascii_output_file
*);
1938 void asciify(macro
*);
1945 class kern_pair_node
1953 kern_pair_node(hunits
, node
*, node
*, statem
*, int, node
* = 0);
1956 node
*merge_glyph_node(glyph_node
*);
1957 node
*add_self(node
*, hyphen_list
**);
1958 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
1959 node
*add_discretionary_hyphen();
1961 node
*last_char_node();
1962 hunits
italic_correction();
1963 hunits
subscript_correction();
1964 void tprint(troff_output_file
*);
1965 hyphenation_type
get_hyphenation_type();
1966 int ends_sentence();
1967 void ascii_print(ascii_output_file
*);
1968 void asciify(macro
*);
1973 void vertical_extent(vunits
*, vunits
*);
1984 dbreak_node(node
*, node
*, statem
*, int, node
* = 0);
1987 node
*merge_glyph_node(glyph_node
*);
1988 node
*add_discretionary_hyphen();
1990 node
*last_char_node();
1991 hunits
italic_correction();
1992 hunits
subscript_correction();
1993 void tprint(troff_output_file
*);
1994 breakpoint
*get_breakpoints(hunits width
, int ns
, breakpoint
*rest
= 0,
1997 int ends_sentence();
1998 void split(int, node
**, node
**);
1999 hyphenation_type
get_hyphenation_type();
2000 void ascii_print(ascii_output_file
*);
2001 void asciify(macro
*);
2008 void *glyph_node::operator new(size_t n
) // TODO -> ObjectCache!
2010 assert(n
== sizeof(glyph_node
));
2012 const int BLOCK
= 1024;
2013 free_list
= (glyph_node
*)new char[sizeof(glyph_node
)*BLOCK
];
2014 for (int i
= 0; i
< BLOCK
- 1; i
++)
2015 free_list
[i
].next
= free_list
+ i
+ 1;
2016 free_list
[BLOCK
-1].next
= 0;
2018 glyph_node
*p
= free_list
;
2019 free_list
= (glyph_node
*)(free_list
->next
);
2024 void *ligature_node::operator new(size_t n
) // TODO ?
2029 void glyph_node::operator delete(void *p
) // TODO -> ObjectCache!
2032 ((glyph_node
*)p
)->next
= free_list
;
2033 free_list
= (glyph_node
*)p
;
2037 void ligature_node::operator delete(void *p
) // TODO ?
2042 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2043 statem
*s
, int pop
, node
*x
)
2044 : charinfo_node(c
, s
, pop
, x
), tf(t
), gcol(gc
), fcol(fc
)
2047 wid
= tf
->get_width(ci
);
2052 glyph_node::glyph_node(charinfo
*c
, tfont
*t
,
2053 color
*gc
, color
*fc
, hunits w
,
2054 statem
*s
, int pop
, node
*x
)
2055 : charinfo_node(c
, s
, pop
, x
), tf(t
), gcol(gc
), fcol(fc
), wid(w
)
2060 node
*glyph_node::copy()
2063 return new glyph_node(ci
, tf
, gcol
, fcol
, wid
, state
, div_nest_level
);
2065 return new glyph_node(ci
, tf
, gcol
, fcol
, state
, div_nest_level
);
2069 node
*glyph_node::merge_self(node
*nd
)
2071 return nd
->merge_glyph_node(this);
2074 int glyph_node::character_type()
2076 return tf
->get_character_type(ci
);
2079 node
*glyph_node::add_self(node
*n
, hyphen_list
**p
)
2081 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
2084 if (n
== 0 || (nn
= n
->merge_glyph_node(this)) == 0) {
2089 nn
= nn
->add_discretionary_hyphen();
2090 hyphen_list
*pp
= *p
;
2096 units
glyph_node::size()
2098 return tf
->get_size().to_units();
2101 hyphen_list
*glyph_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2104 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
2107 tfont
*node::get_tfont()
2112 tfont
*glyph_node::get_tfont()
2117 color
*node::get_glyph_color()
2122 color
*glyph_node::get_glyph_color()
2127 color
*node::get_fill_color()
2132 color
*glyph_node::get_fill_color()
2137 node
*node::merge_glyph_node(glyph_node
*)
2142 node
*glyph_node::merge_glyph_node(glyph_node
*gn
)
2144 if (tf
== gn
->tf
&& gcol
== gn
->gcol
&& fcol
== gn
->fcol
) {
2146 if ((lig
= tf
->get_lig(ci
, gn
->ci
)) != 0) {
2149 return new ligature_node(lig
, tf
, gcol
, fcol
, this, gn
, state
,
2150 gn
->div_nest_level
, next1
);
2153 if (tf
->get_kern(ci
, gn
->ci
, &kern
)) {
2156 return new kern_pair_node(kern
, this, gn
, state
,
2157 gn
->div_nest_level
, next1
);
2166 hunits
glyph_node::width()
2171 return tf
->get_width(ci
);
2175 node
*glyph_node::last_char_node()
2180 void glyph_node::vertical_extent(vunits
*min
, vunits
*max
)
2182 *min
= -tf
->get_char_height(ci
);
2183 *max
= tf
->get_char_depth(ci
);
2186 hunits
glyph_node::skew()
2188 return tf
->get_char_skew(ci
);
2191 hunits
glyph_node::subscript_correction()
2193 return tf
->get_subscript_correction(ci
);
2196 hunits
glyph_node::italic_correction()
2198 return tf
->get_italic_correction(ci
);
2201 hunits
glyph_node::left_italic_correction()
2203 return tf
->get_left_italic_correction(ci
);
2206 hyphenation_type
glyph_node::get_hyphenation_type()
2208 return HYPHEN_MIDDLE
;
2211 void glyph_node::ascii_print(ascii_output_file
*ascii
)
2213 unsigned char c
= ci
->get_ascii_code();
2217 ascii
->outs(ci
->nm
.contents());
2220 void glyph_node::debug_node()
2222 unsigned char c
= ci
->get_ascii_code();
2223 fprintf(stderr
, "{ %s [", type());
2225 fprintf(stderr
, "%c", c
);
2227 fprintf(stderr
, "%s", ci
->nm
.contents());
2229 fprintf(stderr
, " <push_state>");
2231 state
->display_state();
2232 fprintf(stderr
, " nest level %d", div_nest_level
);
2233 fprintf(stderr
, "]}\n");
2237 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2238 node
*gn1
, node
*gn2
, statem
*s
,
2240 : glyph_node(c
, t
, gc
, fc
, s
, pop
, x
), n1(gn1
), n2(gn2
)
2245 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, color
*gc
, color
*fc
,
2246 hunits w
, node
*gn1
, node
*gn2
, statem
*s
,
2248 : glyph_node(c
, t
, gc
, fc
, w
, s
, pop
, x
), n1(gn1
), n2(gn2
)
2253 ligature_node::~ligature_node()
2259 node
*ligature_node::copy()
2262 return new ligature_node(ci
, tf
, gcol
, fcol
, wid
, n1
->copy(), n2
->copy(),
2263 state
, div_nest_level
);
2265 return new ligature_node(ci
, tf
, gcol
, fcol
, n1
->copy(), n2
->copy(),
2266 state
, div_nest_level
);
2270 void ligature_node::ascii_print(ascii_output_file
*ascii
)
2272 n1
->ascii_print(ascii
);
2273 n2
->ascii_print(ascii
);
2276 hyphen_list
*ligature_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2278 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2279 return n1
->get_hyphen_list(hl
, count
);
2282 node
*ligature_node::add_self(node
*n
, hyphen_list
**p
)
2284 n
= n1
->add_self(n
, p
);
2285 n
= n2
->add_self(n
, p
);
2291 kern_pair_node::kern_pair_node(hunits n
, node
*first
, node
*second
,
2292 statem
* s
, int pop
, node
*x
)
2293 : node(x
, s
, pop
), amount(n
), n1(first
), n2(second
)
2297 dbreak_node::dbreak_node(node
*n
, node
*p
, statem
*s
, int pop
, node
*x
)
2298 : node(x
, s
, pop
), none(n
), pre(p
), post(0)
2302 node
*dbreak_node::merge_glyph_node(glyph_node
*gn
)
2304 glyph_node
*gn2
= (glyph_node
*)gn
->copy();
2305 node
*new_none
= none
? none
->merge_glyph_node(gn
) : 0;
2306 node
*new_post
= post
? post
->merge_glyph_node(gn2
) : 0;
2307 if (new_none
== 0 && new_post
== 0) {
2326 node
*kern_pair_node::merge_glyph_node(glyph_node
*gn
)
2328 node
*nd
= n2
->merge_glyph_node(gn
);
2332 nd
= n2
->merge_self(n1
);
2343 hunits
kern_pair_node::italic_correction()
2345 return n2
->italic_correction();
2348 hunits
kern_pair_node::subscript_correction()
2350 return n2
->subscript_correction();
2353 void kern_pair_node::vertical_extent(vunits
*min
, vunits
*max
)
2355 n1
->vertical_extent(min
, max
);
2357 n2
->vertical_extent(&min2
, &max2
);
2364 node
*kern_pair_node::add_discretionary_hyphen()
2366 tfont
*tf
= n2
->get_tfont();
2368 if (tf
->contains(soft_hyphen_char
)) {
2369 color
*gcol
= n2
->get_glyph_color();
2370 color
*fcol
= n2
->get_fill_color();
2374 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
,
2375 state
, div_nest_level
);
2376 node
*nn
= n
->merge_glyph_node(gn
);
2381 return new dbreak_node(this, nn
, state
, div_nest_level
, next1
);
2387 kern_pair_node::~kern_pair_node()
2395 dbreak_node::~dbreak_node()
2397 delete_node_list(pre
);
2398 delete_node_list(post
);
2399 delete_node_list(none
);
2402 node
*kern_pair_node::copy()
2404 return new kern_pair_node(amount
, n1
->copy(), n2
->copy(), state
,
2408 node
*copy_node_list(node
*n
)
2412 node
*nn
= n
->copy();
2426 void delete_node_list(node
*n
)
2435 node
*dbreak_node::copy()
2437 dbreak_node
*p
= new dbreak_node(copy_node_list(none
), copy_node_list(pre
),
2438 state
, div_nest_level
);
2439 p
->post
= copy_node_list(post
);
2443 hyphen_list
*node::get_hyphen_list(hyphen_list
*tail
, int *)
2448 hyphen_list
*kern_pair_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
2450 hyphen_list
*hl
= n2
->get_hyphen_list(tail
, count
);
2451 return n1
->get_hyphen_list(hl
, count
);
2454 class hyphen_inhibitor_node
: public node
{
2456 hyphen_inhibitor_node(node
* = 0);
2462 hyphenation_type
get_hyphenation_type();
2465 hyphen_inhibitor_node::hyphen_inhibitor_node(node
*nd
) : node(nd
)
2469 node
*hyphen_inhibitor_node::copy()
2471 return new hyphen_inhibitor_node
;
2474 int hyphen_inhibitor_node::same(node
*)
2479 const char *hyphen_inhibitor_node::type()
2481 return "hyphen_inhibitor_node";
2484 int hyphen_inhibitor_node::force_tprint()
2489 int hyphen_inhibitor_node::is_tag()
2494 hyphenation_type
hyphen_inhibitor_node::get_hyphenation_type()
2496 return HYPHEN_INHIBIT
;
2499 /* add_discretionary_hyphen methods */
2501 node
*dbreak_node::add_discretionary_hyphen()
2504 post
= post
->add_discretionary_hyphen();
2506 none
= none
->add_discretionary_hyphen();
2510 node
*node::add_discretionary_hyphen()
2512 tfont
*tf
= get_tfont();
2514 return new hyphen_inhibitor_node(this);
2515 if (tf
->contains(soft_hyphen_char
)) {
2516 color
*gcol
= get_glyph_color();
2517 color
*fcol
= get_fill_color();
2521 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
, gcol
, fcol
,
2522 state
, div_nest_level
);
2523 node
*n1
= n
->merge_glyph_node(gn
);
2528 return new dbreak_node(this, n1
, state
, div_nest_level
, next1
);
2533 node
*node::merge_self(node
*)
2538 node
*node::add_self(node
*n
, hyphen_list
** /*p*/)
2544 node
*kern_pair_node::add_self(node
*n
, hyphen_list
**p
)
2546 n
= n1
->add_self(n
, p
);
2547 n
= n2
->add_self(n
, p
);
2553 hunits
node::width()
2558 node
*node::last_char_node()
2563 int node::force_tprint()
2573 hunits
hmotion_node::width()
2580 return points_to_units(10);
2583 void node::debug_node()
2585 fprintf(stderr
, "{ %s ", type());
2587 fprintf(stderr
, " <push_state>");
2589 fprintf(stderr
, " <state>");
2590 fprintf(stderr
, " nest level %d", div_nest_level
);
2591 fprintf(stderr
, " }\n");
2595 void node::debug_node_list()
2606 hunits
kern_pair_node::width()
2608 return n1
->width() + n2
->width() + amount
;
2611 node
*kern_pair_node::last_char_node()
2613 node
*nd
= n2
->last_char_node();
2616 return n1
->last_char_node();
2619 hunits
dbreak_node::width()
2622 for (node
*n
= none
; n
!= 0; n
= n
->next
)
2627 node
*dbreak_node::last_char_node()
2629 for (node
*n
= none
; n
; n
= n
->next
) {
2630 node
*last_node
= n
->last_char_node();
2637 hunits
dbreak_node::italic_correction()
2639 return none
? none
->italic_correction() : H0
;
2642 hunits
dbreak_node::subscript_correction()
2644 return none
? none
->subscript_correction() : H0
;
2647 class italic_corrected_node
2654 italic_corrected_node(node
*, hunits
, statem
*, int, node
* = 0);
2655 ~italic_corrected_node();
2657 void ascii_print(ascii_output_file
*);
2658 void asciify(macro
*);
2660 node
*last_char_node();
2661 void vertical_extent(vunits
*, vunits
*);
2662 int ends_sentence();
2663 int overlaps_horizontally();
2664 int overlaps_vertically();
2666 hyphenation_type
get_hyphenation_type();
2668 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2669 int character_type();
2670 void tprint(troff_output_file
*);
2671 hunits
subscript_correction();
2673 node
*add_self(node
*, hyphen_list
**);
2679 node
*node::add_italic_correction(hunits
*wd
)
2681 hunits ic
= italic_correction();
2688 return new italic_corrected_node(this, ic
, state
, div_nest_level
, next1
);
2692 italic_corrected_node::italic_corrected_node(node
*nn
, hunits xx
, statem
*s
,
2694 : node(p
, s
, pop
), n(nn
), x(xx
)
2699 italic_corrected_node::~italic_corrected_node()
2704 node
*italic_corrected_node::copy()
2706 return new italic_corrected_node(n
->copy(), x
, state
, div_nest_level
);
2709 hunits
italic_corrected_node::width()
2711 return n
->width() + x
;
2714 void italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
2716 n
->vertical_extent(min
, max
);
2719 void italic_corrected_node::tprint(troff_output_file
*out
)
2725 hunits
italic_corrected_node::skew()
2727 return n
->skew() - x
/2;
2730 hunits
italic_corrected_node::subscript_correction()
2732 return n
->subscript_correction() - x
;
2735 void italic_corrected_node::ascii_print(ascii_output_file
*out
)
2737 n
->ascii_print(out
);
2740 int italic_corrected_node::ends_sentence()
2742 return n
->ends_sentence();
2745 int italic_corrected_node::overlaps_horizontally()
2747 return n
->overlaps_horizontally();
2750 int italic_corrected_node::overlaps_vertically()
2752 return n
->overlaps_vertically();
2755 node
*italic_corrected_node::last_char_node()
2757 return n
->last_char_node();
2760 tfont
*italic_corrected_node::get_tfont()
2762 return n
->get_tfont();
2765 hyphenation_type
italic_corrected_node::get_hyphenation_type()
2767 return n
->get_hyphenation_type();
2770 node
*italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
2772 nd
= n
->add_self(nd
, p
);
2773 hunits not_interested
;
2774 nd
= nd
->add_italic_correction(¬_interested
);
2780 hyphen_list
*italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
2783 return n
->get_hyphen_list(tail
, count
);
2786 int italic_corrected_node::character_type()
2788 return n
->character_type();
2791 class break_char_node
2799 break_char_node(node
*, int, color
*, node
* = 0);
2800 break_char_node(node
*, int, color
*, statem
*, int, node
* = 0);
2804 vunits
vertical_width();
2805 node
*last_char_node();
2806 int character_type();
2807 int ends_sentence();
2808 node
*add_self(node
*, hyphen_list
**);
2809 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
2810 void tprint(troff_output_file
*);
2811 void zero_width_tprint(troff_output_file
*);
2812 void ascii_print(ascii_output_file
*);
2813 void asciify(macro
*);
2814 hyphenation_type
get_hyphenation_type();
2815 int overlaps_vertically();
2816 int overlaps_horizontally();
2825 break_char_node::break_char_node(node
*n
, int bc
, color
*c
, node
*x
)
2826 : node(x
), ch(n
), break_code(bc
), col(c
)
2830 break_char_node::break_char_node(node
*n
, int bc
, color
*c
, statem
*s
,
2832 : node(x
, s
, pop
), ch(n
), break_code(bc
), col(c
)
2836 break_char_node::~break_char_node()
2841 node
*break_char_node::copy()
2843 return new break_char_node(ch
->copy(), break_code
, col
, state
,
2847 hunits
break_char_node::width()
2852 vunits
break_char_node::vertical_width()
2854 return ch
->vertical_width();
2857 node
*break_char_node::last_char_node()
2859 return ch
->last_char_node();
2862 int break_char_node::character_type()
2864 return ch
->character_type();
2867 int break_char_node::ends_sentence()
2869 return ch
->ends_sentence();
2872 node
*break_char_node::add_self(node
*n
, hyphen_list
**p
)
2874 assert((*p
)->hyphenation_code
== 0);
2875 if (break_code
& 1) {
2876 if ((*p
)->breakable
|| break_code
& 4) {
2877 n
= new space_node(H0
, col
, n
);
2883 if (break_code
& 2) {
2884 if ((*p
)->breakable
|| break_code
& 4) {
2885 n
= new space_node(H0
, col
, n
);
2889 hyphen_list
*pp
= *p
;
2895 hyphen_list
*break_char_node::get_hyphen_list(hyphen_list
*tail
, int *)
2897 return new hyphen_list(0, tail
);
2900 hyphenation_type
break_char_node::get_hyphenation_type()
2902 return HYPHEN_MIDDLE
;
2905 void break_char_node::ascii_print(ascii_output_file
*ascii
)
2907 ch
->ascii_print(ascii
);
2910 int break_char_node::overlaps_vertically()
2912 return ch
->overlaps_vertically();
2915 int break_char_node::overlaps_horizontally()
2917 return ch
->overlaps_horizontally();
2920 units
break_char_node::size()
2925 tfont
*break_char_node::get_tfont()
2927 return ch
->get_tfont();
2930 node
*extra_size_node::copy()
2932 return new extra_size_node(n
, state
, div_nest_level
);
2935 extra_size_node::extra_size_node(vunits i
, statem
*s
, int pop
)
2936 : node(0, s
, pop
), n(i
)
2940 extra_size_node::extra_size_node(vunits i
)
2945 node
*vertical_size_node::copy()
2947 return new vertical_size_node(n
, state
, div_nest_level
);
2950 vertical_size_node::vertical_size_node(vunits i
, statem
*s
, int pop
)
2951 : node(0, s
, pop
), n(i
)
2955 vertical_size_node::vertical_size_node(vunits i
)
2960 node
*hmotion_node::copy()
2962 return new hmotion_node(n
, was_tab
, unformat
, col
, state
, div_nest_level
);
2965 node
*space_char_hmotion_node::copy()
2967 return new space_char_hmotion_node(n
, col
, state
, div_nest_level
);
2970 vmotion_node::vmotion_node(vunits i
, color
*c
)
2975 vmotion_node::vmotion_node(vunits i
, color
*c
, statem
*s
, int pop
)
2976 : node(0, s
, pop
), n(i
), col(c
)
2980 node
*vmotion_node::copy()
2982 return new vmotion_node(n
, col
, state
, div_nest_level
);
2985 node
*dummy_node::copy()
2987 return new dummy_node
;
2990 node
*transparent_dummy_node::copy()
2992 return new transparent_dummy_node
;
2995 hline_node::~hline_node()
3001 hline_node::hline_node(hunits i
, node
*c
, node
*nxt
)
3002 : node(nxt
), x(i
), n(c
)
3006 hline_node::hline_node(hunits i
, node
*c
, statem
*s
, int pop
, node
*nxt
)
3007 : node(nxt
, s
, pop
), x(i
), n(c
)
3011 node
*hline_node::copy()
3013 return new hline_node(x
, n
? n
->copy() : 0, state
, div_nest_level
);
3016 hunits
hline_node::width()
3018 return x
< H0
? H0
: x
;
3021 vline_node::vline_node(vunits i
, node
*c
, node
*nxt
)
3022 : node(nxt
), x(i
), n(c
)
3026 vline_node::vline_node(vunits i
, node
*c
, statem
*s
, int pop
, node
*nxt
)
3027 : node(nxt
, s
, pop
), x(i
), n(c
)
3031 vline_node::~vline_node()
3037 node
*vline_node::copy()
3039 return new vline_node(x
, n
? n
->copy() : 0, state
, div_nest_level
);
3042 hunits
vline_node::width()
3044 return n
== 0 ? H0
: n
->width();
3047 zero_width_node::zero_width_node(node
*nd
, statem
*s
, int pop
)
3048 : node(0, s
, pop
), n(nd
)
3052 zero_width_node::zero_width_node(node
*nd
)
3057 zero_width_node::~zero_width_node()
3059 delete_node_list(n
);
3062 node
*zero_width_node::copy()
3064 return new zero_width_node(copy_node_list(n
), state
, div_nest_level
);
3067 int node_list_character_type(node
*p
)
3070 for (; p
; p
= p
->next
)
3071 t
|= p
->character_type();
3075 int zero_width_node::character_type()
3077 return node_list_character_type(n
);
3080 void node_list_vertical_extent(node
*p
, vunits
*min
, vunits
*max
)
3084 vunits cur_vpos
= V0
;
3086 for (; p
; p
= p
->next
) {
3087 p
->vertical_extent(&v1
, &v2
);
3094 cur_vpos
+= p
->vertical_width();
3098 void zero_width_node::vertical_extent(vunits
*min
, vunits
*max
)
3100 node_list_vertical_extent(n
, min
, max
);
3103 overstrike_node::overstrike_node()
3104 : list(0), max_width(H0
)
3108 overstrike_node::overstrike_node(statem
*s
, int pop
)
3109 : node(0, s
, pop
), list(0), max_width(H0
)
3113 overstrike_node::~overstrike_node()
3115 delete_node_list(list
);
3118 node
*overstrike_node::copy()
3120 overstrike_node
*on
= new overstrike_node(state
, div_nest_level
);
3121 for (node
*tem
= list
; tem
; tem
= tem
->next
)
3122 on
->overstrike(tem
->copy());
3126 void overstrike_node::overstrike(node
*n
)
3130 hunits w
= n
->width();
3134 for (p
= &list
; *p
; p
= &(*p
)->next
)
3140 hunits
overstrike_node::width()
3145 bracket_node::bracket_node()
3146 : list(0), max_width(H0
)
3150 bracket_node::bracket_node(statem
*s
, int pop
)
3151 : node(0, s
, pop
), list(0), max_width(H0
)
3155 bracket_node::~bracket_node()
3157 delete_node_list(list
);
3160 node
*bracket_node::copy()
3162 bracket_node
*on
= new bracket_node(state
, div_nest_level
);
3163 node
*last_node
= 0;
3167 for (tem
= list
; tem
; tem
= tem
->next
) {
3169 tem
->next
->last
= tem
;
3172 for (tem
= last_node
; tem
; tem
= tem
->last
)
3173 on
->bracket(tem
->copy());
3177 void bracket_node::bracket(node
*n
)
3181 hunits w
= n
->width();
3188 hunits
bracket_node::width()
3198 int node::merge_space(hunits
, hunits
, hunits
)
3204 space_node
*space_node::free_list
= 0;
3206 void *space_node::operator new(size_t n
)
3208 assert(n
== sizeof(space_node
));
3210 free_list
= (space_node
*)new char[sizeof(space_node
)*BLOCK
];
3211 for (int i
= 0; i
< BLOCK
- 1; i
++)
3212 free_list
[i
].next
= free_list
+ i
+ 1;
3213 free_list
[BLOCK
-1].next
= 0;
3215 space_node
*p
= free_list
;
3216 free_list
= (space_node
*)(free_list
->next
);
3221 inline void space_node::operator delete(void *p
)
3224 ((space_node
*)p
)->next
= free_list
;
3225 free_list
= (space_node
*)p
;
3230 space_node::space_node(hunits nn
, color
*c
, node
*p
)
3231 : node(p
, 0, 0), n(nn
), set(0), was_escape_colon(0), col(c
)
3235 space_node::space_node(hunits nn
, color
*c
, statem
*s
, int pop
, node
*p
)
3236 : node(p
, s
, pop
), n(nn
), set(0), was_escape_colon(0), col(c
)
3240 space_node::space_node(hunits nn
, int s
, int flag
, color
*c
, statem
*st
,
3242 : node(p
, st
, pop
), n(nn
), set(s
), was_escape_colon(flag
), col(c
)
3247 space_node::~space_node()
3252 node
*space_node::copy()
3254 return new space_node(n
, set
, was_escape_colon
, col
, state
, div_nest_level
);
3257 int space_node::force_tprint()
3262 int space_node::is_tag()
3267 int space_node::nspaces()
3272 int space_node::merge_space(hunits h
, hunits
, hunits
)
3278 hunits
space_node::width()
3283 void node::spread_space(int*, hunits
*)
3287 void space_node::spread_space(int *n_spaces
, hunits
*desired_space
)
3290 assert(*n_spaces
> 0);
3291 if (*n_spaces
== 1) {
3292 n
+= *desired_space
;
3293 *desired_space
= H0
;
3296 hunits extra
= *desired_space
/ *n_spaces
;
3297 *desired_space
-= extra
;
3305 void node::freeze_space()
3309 void space_node::freeze_space()
3314 void node::is_escape_colon()
3318 void space_node::is_escape_colon()
3320 was_escape_colon
= 1;
3323 diverted_space_node::diverted_space_node(vunits d
, statem
*s
, int pop
,
3325 : node(p
, s
, pop
), n(d
)
3329 diverted_space_node::diverted_space_node(vunits d
, node
*p
)
3334 node
*diverted_space_node::copy()
3336 return new diverted_space_node(n
, state
, div_nest_level
);
3339 diverted_copy_file_node::diverted_copy_file_node(symbol s
, statem
*st
,
3341 : node(p
, st
, pop
), filename(s
)
3345 diverted_copy_file_node::diverted_copy_file_node(symbol s
, node
*p
)
3346 : node(p
), filename(s
)
3350 node
*diverted_copy_file_node::copy()
3352 return new diverted_copy_file_node(filename
, state
, div_nest_level
);
3355 int node::ends_sentence()
3360 int kern_pair_node::ends_sentence()
3362 switch (n2
->ends_sentence()) {
3372 return n1
->ends_sentence();
3375 int node_list_ends_sentence(node
*n
)
3377 for (; n
!= 0; n
= n
->next
)
3378 switch (n
->ends_sentence()) {
3391 int dbreak_node::ends_sentence()
3393 return node_list_ends_sentence(none
);
3396 int node::overlaps_horizontally()
3401 int node::overlaps_vertically()
3406 int node::discardable()
3411 int space_node::discardable()
3416 vunits
node::vertical_width()
3421 vunits
vline_node::vertical_width()
3426 vunits
vmotion_node::vertical_width()
3431 int node::set_unformat_flag()
3436 int node::character_type()
3441 hunits
node::subscript_correction()
3446 hunits
node::italic_correction()
3451 hunits
node::left_italic_correction()
3461 /* vertical_extent methods */
3463 void node::vertical_extent(vunits
*min
, vunits
*max
)
3465 vunits v
= vertical_width();
3476 void vline_node::vertical_extent(vunits
*min
, vunits
*max
)
3479 node::vertical_extent(min
, max
);
3482 n
->vertical_extent(&cmin
, &cmax
);
3483 vunits h
= n
->size();
3490 // we print the first character and then move up, so
3492 // we print the last character and then move up h
3505 // we move down by h and then print the first character, so
3515 /* ascii_print methods */
3517 static void ascii_print_reverse_node_list(ascii_output_file
*ascii
, node
*n
)
3521 ascii_print_reverse_node_list(ascii
, n
->next
);
3522 n
->ascii_print(ascii
);
3525 void dbreak_node::ascii_print(ascii_output_file
*ascii
)
3527 ascii_print_reverse_node_list(ascii
, none
);
3530 void kern_pair_node::ascii_print(ascii_output_file
*ascii
)
3532 n1
->ascii_print(ascii
);
3533 n2
->ascii_print(ascii
);
3536 void node::ascii_print(ascii_output_file
*)
3540 void space_node::ascii_print(ascii_output_file
*ascii
)
3546 void hmotion_node::ascii_print(ascii_output_file
*ascii
)
3548 // this is pretty arbitrary
3549 if (n
>= points_to_units(2))
3553 void space_char_hmotion_node::ascii_print(ascii_output_file
*ascii
)
3558 /* asciify methods */
3560 void node::asciify(macro
*m
)
3565 void glyph_node::asciify(macro
*m
)
3567 unsigned char c
= ci
->get_asciify_code();
3569 c
= ci
->get_ascii_code();
3578 void kern_pair_node::asciify(macro
*m
)
3586 static void asciify_reverse_node_list(macro
*m
, node
*n
)
3590 asciify_reverse_node_list(m
, n
->next
);
3594 void dbreak_node::asciify(macro
*m
)
3596 asciify_reverse_node_list(m
, none
);
3601 void ligature_node::asciify(macro
*m
)
3609 void break_char_node::asciify(macro
*m
)
3616 void italic_corrected_node::asciify(macro
*m
)
3623 void left_italic_corrected_node::asciify(macro
*m
)
3632 void hmotion_node::asciify(macro
*m
)
3642 space_char_hmotion_node::space_char_hmotion_node(hunits i
, color
*c
,
3645 : hmotion_node(i
, c
, s
, pop
, nxt
)
3649 space_char_hmotion_node::space_char_hmotion_node(hunits i
, color
*c
,
3651 : hmotion_node(i
, c
, 0, 0, nxt
)
3655 void space_char_hmotion_node::asciify(macro
*m
)
3657 m
->append(ESCAPE_SPACE
);
3661 void space_node::asciify(macro
*m
)
3663 if (was_escape_colon
) {
3664 m
->append(ESCAPE_COLON
);
3671 void word_space_node::asciify(macro
*m
)
3673 for (width_list
*w
= orig_width
; w
; w
= w
->next
)
3678 void unbreakable_space_node::asciify(macro
*m
)
3680 m
->append(ESCAPE_TILDE
);
3684 void line_start_node::asciify(macro
*)
3689 void vertical_size_node::asciify(macro
*)
3694 breakpoint
*node::get_breakpoints(hunits
/*width*/, int /*nspaces*/,
3695 breakpoint
*rest
, int /*is_inner*/)
3705 breakpoint
*space_node::get_breakpoints(hunits wd
, int ns
,
3706 breakpoint
*rest
, int is_inner
)
3708 if (next
&& next
->discardable())
3710 breakpoint
*bp
= new breakpoint
;
3717 bp
->index
= rest
->index
+ 1;
3727 int space_node::nbreaks()
3729 if (next
&& next
->discardable())
3735 static breakpoint
*node_list_get_breakpoints(node
*p
, hunits
*widthp
,
3736 int ns
, breakpoint
*rest
)
3739 rest
= p
->get_breakpoints(*widthp
,
3741 node_list_get_breakpoints(p
->next
, widthp
, ns
,
3744 *widthp
+= p
->width();
3749 breakpoint
*dbreak_node::get_breakpoints(hunits wd
, int ns
,
3750 breakpoint
*rest
, int is_inner
)
3752 breakpoint
*bp
= new breakpoint
;
3755 for (node
*tem
= pre
; tem
!= 0; tem
= tem
->next
)
3756 bp
->width
+= tem
->width();
3761 bp
->index
= rest
->index
+ 1;
3768 return node_list_get_breakpoints(none
, &wd
, ns
, bp
);
3771 int dbreak_node::nbreaks()
3774 for (node
*tem
= none
; tem
!= 0; tem
= tem
->next
)
3775 i
+= tem
->nbreaks();
3779 void node::split(int /*where*/, node
** /*prep*/, node
** /*postp*/)
3784 void space_node::split(int where
, node
**pre
, node
**post
)
3792 static void node_list_split(node
*p
, int *wherep
, node
**prep
, node
**postp
)
3796 int nb
= p
->nbreaks();
3797 node_list_split(p
->next
, wherep
, prep
, postp
);
3802 else if (*wherep
< nb
) {
3804 p
->split(*wherep
, prep
, postp
);
3813 void dbreak_node::split(int where
, node
**prep
, node
**postp
)
3823 for (tem
= pre
; tem
->next
!= 0; tem
= tem
->next
)
3834 node_list_split(none
, &where
, prep
, postp
);
3840 hyphenation_type
node::get_hyphenation_type()
3842 return HYPHEN_BOUNDARY
;
3845 hyphenation_type
dbreak_node::get_hyphenation_type()
3847 return HYPHEN_INHIBIT
;
3850 hyphenation_type
kern_pair_node::get_hyphenation_type()
3852 return HYPHEN_MIDDLE
;
3855 hyphenation_type
dummy_node::get_hyphenation_type()
3857 return HYPHEN_MIDDLE
;
3860 hyphenation_type
transparent_dummy_node::get_hyphenation_type()
3862 return HYPHEN_MIDDLE
;
3865 hyphenation_type
hmotion_node::get_hyphenation_type()
3867 return HYPHEN_MIDDLE
;
3870 hyphenation_type
space_char_hmotion_node::get_hyphenation_type()
3872 return HYPHEN_MIDDLE
;
3875 hyphenation_type
overstrike_node::get_hyphenation_type()
3877 return HYPHEN_MIDDLE
;
3880 hyphenation_type
space_node::get_hyphenation_type()
3882 if (was_escape_colon
)
3883 return HYPHEN_MIDDLE
;
3884 return HYPHEN_BOUNDARY
;
3887 hyphenation_type
unbreakable_space_node::get_hyphenation_type()
3889 return HYPHEN_MIDDLE
;
3892 int node::interpret(macro
*)
3897 special_node::special_node(const macro
&m
, int n
)
3898 : mac(m
), no_init_string(n
)
3900 font_size fs
= curenv
->get_font_size();
3901 int char_height
= curenv
->get_char_height();
3902 int char_slant
= curenv
->get_char_slant();
3903 int fontno
= env_definite_font(curenv
);
3904 tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fontno
);
3905 if (curenv
->is_composite())
3906 tf
= tf
->get_plain();
3907 gcol
= curenv
->get_glyph_color();
3908 fcol
= curenv
->get_fill_color();
3912 special_node::special_node(const macro
&m
, tfont
*t
,
3913 color
*gc
, color
*fc
,
3916 : node(0, s
, pop
), mac(m
), tf(t
), gcol(gc
), fcol(fc
), no_init_string(n
)
3921 int special_node::same(node
*n
)
3923 return mac
== ((special_node
*)n
)->mac
3924 && tf
== ((special_node
*)n
)->tf
3925 && gcol
== ((special_node
*)n
)->gcol
3926 && fcol
== ((special_node
*)n
)->fcol
3927 && no_init_string
== ((special_node
*)n
)->no_init_string
;
3930 const char *special_node::type()
3932 return "special_node";
3935 int special_node::ends_sentence()
3940 int special_node::force_tprint()
3945 int special_node::is_tag()
3950 node
*special_node::copy()
3952 return new special_node(mac
, tf
, gcol
, fcol
, state
, div_nest_level
,
3956 void special_node::tprint_start(troff_output_file
*out
)
3958 out
->start_special(tf
, gcol
, fcol
, no_init_string
);
3961 void special_node::tprint_char(troff_output_file
*out
, unsigned char c
)
3963 out
->special_char(c
);
3966 void special_node::tprint_end(troff_output_file
*out
)
3971 tfont
*special_node::get_tfont()
3978 suppress_node::suppress_node(int on_or_off
, int issue_limits
)
3979 : is_on(on_or_off
), emit_limits(issue_limits
), filename(0), position(0),
3984 suppress_node::suppress_node(symbol f
, char p
, int id
)
3985 : is_on(2), emit_limits(0), filename(f
), position(p
), image_id(id
)
3990 suppress_node::suppress_node(int issue_limits
, int on_or_off
,
3991 symbol f
, char p
, int id
,
3993 : node(0, s
, pop
), is_on(on_or_off
), emit_limits(issue_limits
), filename(f
),
3994 position(p
), image_id(id
)
3998 int suppress_node::same(node
*n
)
4000 return ((is_on
== ((suppress_node
*)n
)->is_on
)
4001 && (emit_limits
== ((suppress_node
*)n
)->emit_limits
)
4002 && (filename
== ((suppress_node
*)n
)->filename
)
4003 && (position
== ((suppress_node
*)n
)->position
)
4004 && (image_id
== ((suppress_node
*)n
)->image_id
));
4007 const char *suppress_node::type()
4009 return "suppress_node";
4012 node
*suppress_node::copy()
4014 return new suppress_node(emit_limits
, is_on
, filename
, position
, image_id
,
4015 state
, div_nest_level
);
4020 tag_node::tag_node()
4026 tag_node::tag_node(string s
, int delay
)
4027 : tag_string(s
), delayed(delay
)
4029 is_special
= !delay
;
4032 tag_node::tag_node(string s
, statem
*st
, int pop
, int delay
)
4033 : node(0, st
, pop
), tag_string(s
), delayed(delay
)
4035 is_special
= !delay
;
4038 node
*tag_node::copy()
4040 return new tag_node(tag_string
, state
, div_nest_level
, delayed
);
4043 void tag_node::tprint(troff_output_file
*out
)
4046 out
->add_to_tag_list(tag_string
);
4048 out
->state
.add_tag(out
->fp
, tag_string
);
4051 int tag_node::same(node
*nd
)
4053 return tag_string
== ((tag_node
*)nd
)->tag_string
4054 && delayed
== ((tag_node
*)nd
)->delayed
;
4057 const char *tag_node::type()
4062 int tag_node::force_tprint()
4067 int tag_node::is_tag()
4072 int tag_node::ends_sentence()
4077 int get_reg_int(const char *p
)
4079 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
4081 if (r
&& (r
->get_value(&prev_value
)))
4082 return (int)prev_value
;
4084 warning(WARN_REG
, "number register `%1' not defined", p
);
4088 const char *get_reg_str(const char *p
)
4090 reg
*r
= (reg
*)number_reg_dictionary
.lookup(p
);
4092 return r
->get_string();
4094 warning(WARN_REG
, "register `%1' not defined", p
);
4098 void suppress_node::put(troff_output_file
*out
, const char *s
)
4101 while (s
[i
] != (char)0) {
4102 out
->special_char(s
[i
]);
4108 * We need to remember the start of the image and its name.
4111 static char last_position
= 0;
4112 static const char *last_image_filename
= 0;
4113 static int last_image_id
= 0;
4115 inline int min(int a
, int b
)
4117 return a
< b
? a
: b
;
4121 * tprint - if (is_on == 2)
4122 * remember current position (l, r, c, i) and filename
4128 * emit postscript bounds for image
4130 * if (suppress boolean differs from current state)
4133 * record current page
4134 * set low water mark.
4137 void suppress_node::tprint(troff_output_file
*out
)
4139 int current_page
= topdiv
->get_page_number();
4140 // firstly check to see whether this suppress node contains
4141 // an image filename & position.
4143 // remember position and filename
4144 last_position
= position
;
4145 char *tem
= (char *)last_image_filename
;
4146 last_image_filename
= strsave(filename
.contents());
4149 last_image_id
= image_id
;
4150 // printf("start of image and page = %d\n", current_page);
4153 // now check whether the suppress node requires us to issue limits.
4156 // remember that the filename will contain a %d in which the
4157 // last_image_id is placed
4158 if (last_image_filename
== (char *) 0)
4161 sprintf(name
, last_image_filename
, last_image_id
);
4163 switch (last_position
) {
4165 out
->start_special();
4166 put(out
, "devtag:.centered-image");
4169 out
->start_special();
4170 put(out
, "devtag:.right-image");
4173 out
->start_special();
4174 put(out
, "devtag:.left-image");
4182 out
->start_special();
4183 put(out
, "devtag:.auto-image ");
4188 // postscript (or other device)
4189 if (suppress_start_page
> 0 && current_page
!= suppress_start_page
)
4190 error("suppression limit registers span more than one page;\n"
4191 "image description %1 will be wrong", image_no
);
4192 // if (topdiv->get_page_number() != suppress_start_page)
4193 // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
4194 // topdiv->get_page_number(), suppress_start_page);
4196 // remember that the filename will contain a %d in which the
4197 // image_no is placed
4199 "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
4200 topdiv
->get_page_number(),
4201 get_reg_int("opminx"), get_reg_int("opminy"),
4202 get_reg_int("opmaxx"), get_reg_int("opmaxy"),
4203 // page offset + line length
4204 get_reg_int(".o") + get_reg_int(".l"),
4205 name
, hresolution
, vresolution
, get_reg_str(".F"));
4212 // lastly we reset the output registers
4213 reset_output_registers();
4217 suppress_start_page
= current_page
;
4222 int suppress_node::force_tprint()
4227 int suppress_node::is_tag()
4232 hunits
suppress_node::width()
4237 /* composite_node */
4239 class composite_node
4240 : public charinfo_node
4246 composite_node(node
*, charinfo
*, tfont
*, statem
*, int, node
* = 0);
4250 node
*last_char_node();
4252 void tprint(troff_output_file
*);
4253 hyphenation_type
get_hyphenation_type();
4254 void ascii_print(ascii_output_file
*);
4255 void asciify(macro
*);
4256 hyphen_list
*get_hyphen_list(hyphen_list
*, int *);
4257 node
*add_self(node
*, hyphen_list
**);
4263 void vertical_extent(vunits
*, vunits
*);
4264 vunits
vertical_width();
4267 composite_node::composite_node(node
*p
, charinfo
*c
, tfont
*t
, statem
*s
,
4269 : charinfo_node(c
, s
, pop
, x
), n(p
), tf(t
)
4273 composite_node::~composite_node()
4275 delete_node_list(n
);
4278 node
*composite_node::copy()
4280 return new composite_node(copy_node_list(n
), ci
, tf
, state
, div_nest_level
);
4283 hunits
composite_node::width()
4286 if (tf
->get_constant_space(&x
))
4289 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4292 if (tf
->get_bold(&offset
))
4294 x
+= tf
->get_track_kern();
4298 node
*composite_node::last_char_node()
4303 vunits
composite_node::vertical_width()
4306 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4307 v
+= tem
->vertical_width();
4311 units
composite_node::size()
4313 return tf
->get_size().to_units();
4316 hyphenation_type
composite_node::get_hyphenation_type()
4318 return HYPHEN_MIDDLE
;
4321 void composite_node::asciify(macro
*m
)
4323 unsigned char c
= ci
->get_asciify_code();
4325 c
= ci
->get_ascii_code();
4334 void composite_node::ascii_print(ascii_output_file
*ascii
)
4336 unsigned char c
= ci
->get_ascii_code();
4340 ascii
->outs(ci
->nm
.contents());
4344 hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
, int *count
)
4347 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
4350 node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
4352 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
4356 nn
= nn
->add_discretionary_hyphen();
4357 hyphen_list
*pp
= *p
;
4363 tfont
*composite_node::get_tfont()
4368 node
*reverse_node_list(node
*n
)
4380 void composite_node::vertical_extent(vunits
*minimum
, vunits
*maximum
)
4382 n
= reverse_node_list(n
);
4383 node_list_vertical_extent(n
, minimum
, maximum
);
4384 n
= reverse_node_list(n
);
4387 width_list::width_list(hunits w
, hunits s
)
4388 : width(w
), sentence_width(s
), next(0)
4392 width_list::width_list(width_list
*w
)
4393 : width(w
->width
), sentence_width(w
->sentence_width
), next(0)
4397 word_space_node::word_space_node(hunits d
, color
*c
, width_list
*w
, node
*x
)
4398 : space_node(d
, c
, x
), orig_width(w
), unformat(0)
4402 word_space_node::word_space_node(hunits d
, int s
, color
*c
, width_list
*w
,
4403 int flag
, statem
*st
, int pop
, node
*x
)
4404 : space_node(d
, s
, 0, c
, st
, pop
, x
), orig_width(w
), unformat(flag
)
4408 word_space_node::~word_space_node()
4410 width_list
*w
= orig_width
;
4412 width_list
*tmp
= w
;
4418 node
*word_space_node::copy()
4420 assert(orig_width
!= 0);
4421 width_list
*w_old_curr
= orig_width
;
4422 width_list
*w_new_curr
= new width_list(w_old_curr
);
4423 width_list
*w_new
= w_new_curr
;
4424 w_old_curr
= w_old_curr
->next
;
4425 while (w_old_curr
!= 0) {
4426 w_new_curr
->next
= new width_list(w_old_curr
);
4427 w_new_curr
= w_new_curr
->next
;
4428 w_old_curr
= w_old_curr
->next
;
4430 return new word_space_node(n
, set
, col
, w_new
, unformat
, state
,
4434 int word_space_node::set_unformat_flag()
4440 void word_space_node::tprint(troff_output_file
*out
)
4442 out
->fill_color(col
);
4447 int word_space_node::merge_space(hunits h
, hunits sw
, hunits ssw
)
4450 assert(orig_width
!= 0);
4451 width_list
*w
= orig_width
;
4452 for (; w
->next
; w
= w
->next
)
4454 w
->next
= new width_list(sw
, ssw
);
4458 unbreakable_space_node::unbreakable_space_node(hunits d
, color
*c
, node
*x
)
4459 : word_space_node(d
, c
, 0, x
)
4463 unbreakable_space_node::unbreakable_space_node(hunits d
, int s
,
4464 color
*c
, statem
*st
, int pop
,
4466 : word_space_node(d
, s
, c
, 0, 0, st
, pop
, x
)
4470 node
*unbreakable_space_node::copy()
4472 return new unbreakable_space_node(n
, set
, col
, state
, div_nest_level
);
4475 int unbreakable_space_node::force_tprint()
4480 int unbreakable_space_node::is_tag()
4485 breakpoint
*unbreakable_space_node::get_breakpoints(hunits
, int,
4486 breakpoint
*rest
, int)
4491 int unbreakable_space_node::nbreaks()
4496 void unbreakable_space_node::split(int, node
**, node
**)
4501 int unbreakable_space_node::merge_space(hunits
, hunits
, hunits
)
4510 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4511 color
*gc
, color
*fc
)
4512 : npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4514 point
= new hvpair
[npoints
];
4515 for (int i
= 0; i
< npoints
; i
++)
4519 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
,
4520 color
*gc
, color
*fc
, statem
*st
, int pop
)
4521 : node(0, st
, pop
), npoints(np
), sz(s
), gcol(gc
), fcol(fc
), code(c
)
4523 point
= new hvpair
[npoints
];
4524 for (int i
= 0; i
< npoints
; i
++)
4528 int draw_node::same(node
*n
)
4530 draw_node
*nd
= (draw_node
*)n
;
4531 if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
4532 || gcol
!= nd
->gcol
|| fcol
!= nd
->fcol
)
4534 for (int i
= 0; i
< npoints
; i
++)
4535 if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
4540 const char *draw_node::type()
4545 int draw_node::force_tprint()
4550 int draw_node::is_tag()
4555 draw_node::~draw_node()
4561 hunits
draw_node::width()
4564 for (int i
= 0; i
< npoints
; i
++)
4569 vunits
draw_node::vertical_width()
4574 for (int i
= 0; i
< npoints
; i
++)
4579 node
*draw_node::copy()
4581 return new draw_node(code
, point
, npoints
, sz
, gcol
, fcol
, state
,
4585 void draw_node::tprint(troff_output_file
*out
)
4587 out
->draw(code
, point
, npoints
, sz
, gcol
, fcol
);
4590 /* tprint methods */
4592 void glyph_node::tprint(troff_output_file
*out
)
4594 tfont
*ptf
= tf
->get_plain();
4596 out
->put_char_width(ci
, ptf
, gcol
, fcol
, width(), H0
);
4599 int bold
= tf
->get_bold(&offset
);
4600 hunits w
= ptf
->get_width(ci
);
4603 int cs
= tf
->get_constant_space(&x
);
4613 k
= tf
->get_track_kern();
4615 out
->put_char(ci
, ptf
, gcol
, fcol
);
4618 out
->put_char_width(ci
, ptf
, gcol
, fcol
, w
, k
);
4622 void glyph_node::zero_width_tprint(troff_output_file
*out
)
4624 tfont
*ptf
= tf
->get_plain();
4626 int bold
= tf
->get_bold(&offset
);
4628 int cs
= tf
->get_constant_space(&x
);
4630 x
-= ptf
->get_width(ci
);
4636 out
->put_char(ci
, ptf
, gcol
, fcol
);
4639 out
->put_char(ci
, ptf
, gcol
, fcol
);
4640 out
->right(-offset
);
4646 void break_char_node::tprint(troff_output_file
*t
)
4651 void break_char_node::zero_width_tprint(troff_output_file
*t
)
4653 ch
->zero_width_tprint(t
);
4656 void hline_node::tprint(troff_output_file
*out
)
4666 hunits w
= n
->width();
4668 error("horizontal line drawing character must have positive width");
4679 out
->right(xx
- xx2
);
4682 hunits rem
= x
- w
*i
;
4684 if (n
->overlaps_horizontally()) {
4687 out
->right(rem
- w
);
4698 void vline_node::tprint(troff_output_file
*out
)
4704 vunits h
= n
->size();
4705 int overlaps
= n
->overlaps_vertically();
4710 vunits rem
= y
- i
*h
;
4712 out
->right(n
->width());
4717 n
->zero_width_tprint(out
);
4721 n
->zero_width_tprint(out
);
4730 out
->down(-h
- rem
);
4736 vunits rem
= y
- i
*h
;
4739 out
->right(n
->width());
4744 n
->zero_width_tprint(out
);
4747 n
->zero_width_tprint(out
);
4756 void zero_width_node::tprint(troff_output_file
*out
)
4761 n
->zero_width_tprint(out
);
4764 int hpos
= out
->get_hpos();
4765 int vpos
= out
->get_vpos();
4771 out
->moveto(hpos
, vpos
);
4774 void overstrike_node::tprint(troff_output_file
*out
)
4777 for (node
*tem
= list
; tem
; tem
= tem
->next
) {
4778 hunits x
= (max_width
- tem
->width())/2;
4779 out
->right(x
- pos
);
4781 tem
->zero_width_tprint(out
);
4783 out
->right(max_width
- pos
);
4786 void bracket_node::tprint(troff_output_file
*out
)
4792 for (tem
= list
; tem
; tem
= tem
->next
)
4794 vunits h
= list
->size();
4795 vunits totalh
= h
*npieces
;
4796 vunits y
= (totalh
- h
)/2;
4798 for (tem
= list
; tem
; tem
= tem
->next
) {
4799 tem
->zero_width_tprint(out
);
4802 out
->right(max_width
);
4803 out
->down(totalh
- y
);
4806 void node::tprint(troff_output_file
*)
4810 void node::zero_width_tprint(troff_output_file
*out
)
4812 int hpos
= out
->get_hpos();
4813 int vpos
= out
->get_vpos();
4815 out
->moveto(hpos
, vpos
);
4818 void space_node::tprint(troff_output_file
*out
)
4820 out
->fill_color(col
);
4824 void hmotion_node::tprint(troff_output_file
*out
)
4826 out
->fill_color(col
);
4830 void space_char_hmotion_node::tprint(troff_output_file
*out
)
4832 out
->fill_color(col
);
4834 // we emit the space width as a negative glyph index
4838 out
->put(-n
.to_units());
4844 void vmotion_node::tprint(troff_output_file
*out
)
4846 out
->fill_color(col
);
4850 void kern_pair_node::tprint(troff_output_file
*out
)
4857 static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
4861 tprint_reverse_node_list(out
, n
->next
);
4865 void dbreak_node::tprint(troff_output_file
*out
)
4867 tprint_reverse_node_list(out
, none
);
4870 void composite_node::tprint(troff_output_file
*out
)
4873 int is_bold
= tf
->get_bold(&bold_offset
);
4874 hunits track_kern
= tf
->get_track_kern();
4875 hunits constant_space
;
4876 int is_constant_spaced
= tf
->get_constant_space(&constant_space
);
4878 if (is_constant_spaced
) {
4880 for (node
*tem
= n
; tem
; tem
= tem
->next
)
4889 int hpos
= out
->get_hpos();
4890 int vpos
= out
->get_vpos();
4891 tprint_reverse_node_list(out
, n
);
4892 out
->moveto(hpos
, vpos
);
4893 out
->right(bold_offset
);
4895 tprint_reverse_node_list(out
, n
);
4896 if (is_constant_spaced
)
4899 out
->right(track_kern
);
4902 node
*make_composite_node(charinfo
*s
, environment
*env
)
4904 int fontno
= env_definite_font(env
);
4906 error("no current font");
4909 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4910 node
*n
= charinfo_to_node_list(s
, env
);
4911 font_size fs
= env
->get_font_size();
4912 int char_height
= env
->get_char_height();
4913 int char_slant
= env
->get_char_slant();
4914 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
,
4916 if (env
->is_composite())
4917 tf
= tf
->get_plain();
4918 return new composite_node(n
, s
, tf
, 0, 0, 0);
4921 node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
4923 int fontno
= env_definite_font(env
);
4925 error("no current font");
4928 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
4930 int found
= font_table
[fontno
]->contains(s
);
4932 macro
*mac
= s
->get_macro();
4933 if (mac
&& s
->is_fallback())
4934 return make_composite_node(s
, env
);
4935 if (s
->numbered()) {
4936 if (!no_error_message
)
4937 warning(WARN_CHAR
, "can't find numbered character %1",
4941 special_font_list
*sf
= font_table
[fontno
]->sf
;
4942 while (sf
!= 0 && !found
) {
4945 found
= font_table
[fn
]->contains(s
);
4949 symbol f
= font_table
[fontno
]->get_name();
4950 string
gl(f
.contents());
4952 gl
+= s
->nm
.contents();
4954 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
4955 if (ci
&& ci
->get_macro())
4956 return make_composite_node(ci
, env
);
4959 sf
= global_special_fonts
;
4960 while (sf
!= 0 && !found
) {
4963 found
= font_table
[fn
]->contains(s
);
4968 if (mac
&& s
->is_special())
4969 return make_composite_node(s
, env
);
4971 for (fn
= 0; fn
< font_table_size
; fn
++)
4973 && font_table
[fn
]->is_special()
4974 && font_table
[fn
]->contains(s
)) {
4980 if (!no_error_message
&& s
->first_time_not_found()) {
4981 unsigned char input_code
= s
->get_ascii_code();
4982 if (input_code
!= 0) {
4983 if (csgraph(input_code
))
4984 warning(WARN_CHAR
, "can't find character `%1'", input_code
);
4986 warning(WARN_CHAR
, "can't find character with input code %1",
4989 else if (s
->nm
.contents()) {
4990 const char *nm
= s
->nm
.contents();
4991 const char *backslash
= (nm
[1] == 0) ? "\\" : "";
4992 warning(WARN_CHAR
, "can't find special character `%1%2'",
4999 font_size fs
= env
->get_font_size();
5000 int char_height
= env
->get_char_height();
5001 int char_slant
= env
->get_char_slant();
5002 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
5003 if (env
->is_composite())
5004 tf
= tf
->get_plain();
5005 color
*gcol
= env
->get_glyph_color();
5006 color
*fcol
= env
->get_fill_color();
5007 return new glyph_node(s
, tf
, gcol
, fcol
, 0, 0);
5010 node
*make_node(charinfo
*ci
, environment
*env
)
5012 switch (ci
->get_special_translation()) {
5013 case charinfo::TRANSLATE_SPACE
:
5014 return new space_char_hmotion_node(env
->get_space_width(),
5015 env
->get_fill_color());
5016 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
5017 return new unbreakable_space_node(env
->get_space_width(),
5018 env
->get_fill_color());
5019 case charinfo::TRANSLATE_DUMMY
:
5020 return new dummy_node
;
5021 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
5022 error("translation to \\% ignored in this context");
5025 charinfo
*tem
= ci
->get_translation();
5028 macro
*mac
= ci
->get_macro();
5029 if (mac
&& ci
->is_normal())
5030 return make_composite_node(ci
, env
);
5032 return make_glyph_node(ci
, env
);
5035 int character_exists(charinfo
*ci
, environment
*env
)
5037 if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
5039 charinfo
*tem
= ci
->get_translation();
5042 if (ci
->get_macro())
5044 node
*nd
= make_glyph_node(ci
, env
, 1);
5052 node
*node::add_char(charinfo
*ci
, environment
*env
,
5053 hunits
*widthp
, int *spacep
, node
**glyph_comp_np
)
5056 switch (ci
->get_special_translation()) {
5057 case charinfo::TRANSLATE_SPACE
:
5058 res
= new space_char_hmotion_node(env
->get_space_width(),
5059 env
->get_fill_color(), this);
5060 *widthp
+= res
->width();
5062 case charinfo::TRANSLATE_STRETCHABLE_SPACE
:
5063 res
= new unbreakable_space_node(env
->get_space_width(),
5064 env
->get_fill_color(), this);
5065 res
->freeze_space();
5066 *widthp
+= res
->width();
5067 *spacep
+= res
->nspaces();
5069 case charinfo::TRANSLATE_DUMMY
:
5070 return new dummy_node(this);
5071 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
5072 return add_discretionary_hyphen();
5074 charinfo
*tem
= ci
->get_translation();
5077 macro
*mac
= ci
->get_macro();
5078 if (mac
&& ci
->is_normal()) {
5079 res
= make_composite_node(ci
, env
);
5082 *widthp
+= res
->width();
5084 *glyph_comp_np
= res
;
5088 *glyph_comp_np
= res
;
5093 node
*gn
= make_glyph_node(ci
, env
);
5097 hunits old_width
= width();
5098 node
*p
= gn
->merge_self(this);
5100 *widthp
+= gn
->width();
5105 *widthp
+= p
->width() - old_width
;
5109 *glyph_comp_np
= res
;
5113 if (ci
->can_break_before())
5115 if (ci
->can_break_after())
5117 if (ci
->ignore_hcodes())
5120 node
*next1
= res
->next
;
5122 res
= new break_char_node(res
, break_code
, env
->get_fill_color(), next1
);
5128 int same_node(node
*n1
, node
*n2
)
5132 return n1
->type() == n2
->type() && n1
->same(n2
);
5140 int same_node_list(node
*n1
, node
*n2
)
5143 if (n1
->type() != n2
->type() || !n1
->same(n2
))
5151 int extra_size_node::same(node
*nd
)
5153 return n
== ((extra_size_node
*)nd
)->n
;
5156 const char *extra_size_node::type()
5158 return "extra_size_node";
5161 int extra_size_node::force_tprint()
5166 int extra_size_node::is_tag()
5171 int vertical_size_node::same(node
*nd
)
5173 return n
== ((vertical_size_node
*)nd
)->n
;
5176 const char *vertical_size_node::type()
5178 return "vertical_size_node";
5181 int vertical_size_node::set_unformat_flag()
5186 int vertical_size_node::force_tprint()
5191 int vertical_size_node::is_tag()
5196 int hmotion_node::same(node
*nd
)
5198 return n
== ((hmotion_node
*)nd
)->n
5199 && col
== ((hmotion_node
*)nd
)->col
;
5202 const char *hmotion_node::type()
5204 return "hmotion_node";
5207 int hmotion_node::set_unformat_flag()
5213 int hmotion_node::force_tprint()
5218 int hmotion_node::is_tag()
5223 node
*hmotion_node::add_self(node
*nd
, hyphen_list
**p
)
5226 hyphen_list
*pp
= *p
;
5232 hyphen_list
*hmotion_node::get_hyphen_list(hyphen_list
*tail
, int *)
5234 return new hyphen_list(0, tail
);
5237 int space_char_hmotion_node::same(node
*nd
)
5239 return n
== ((space_char_hmotion_node
*)nd
)->n
5240 && col
== ((space_char_hmotion_node
*)nd
)->col
;
5243 const char *space_char_hmotion_node::type()
5245 return "space_char_hmotion_node";
5248 int space_char_hmotion_node::force_tprint()
5253 int space_char_hmotion_node::is_tag()
5258 node
*space_char_hmotion_node::add_self(node
*nd
, hyphen_list
**p
)
5261 hyphen_list
*pp
= *p
;
5267 hyphen_list
*space_char_hmotion_node::get_hyphen_list(hyphen_list
*tail
,
5270 return new hyphen_list(0, tail
);
5273 int vmotion_node::same(node
*nd
)
5275 return n
== ((vmotion_node
*)nd
)->n
5276 && col
== ((vmotion_node
*)nd
)->col
;
5279 const char *vmotion_node::type()
5281 return "vmotion_node";
5284 int vmotion_node::force_tprint()
5289 int vmotion_node::is_tag()
5294 int hline_node::same(node
*nd
)
5296 return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
5299 const char *hline_node::type()
5301 return "hline_node";
5304 int hline_node::force_tprint()
5309 int hline_node::is_tag()
5314 int vline_node::same(node
*nd
)
5316 return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
5319 const char *vline_node::type()
5321 return "vline_node";
5324 int vline_node::force_tprint()
5329 int vline_node::is_tag()
5334 int dummy_node::same(node
* /*nd*/)
5339 const char *dummy_node::type()
5341 return "dummy_node";
5344 int dummy_node::force_tprint()
5349 int dummy_node::is_tag()
5354 int transparent_dummy_node::same(node
* /*nd*/)
5359 const char *transparent_dummy_node::type()
5361 return "transparent_dummy_node";
5364 int transparent_dummy_node::force_tprint()
5369 int transparent_dummy_node::is_tag()
5374 int transparent_dummy_node::ends_sentence()
5379 int zero_width_node::same(node
*nd
)
5381 return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
5384 const char *zero_width_node::type()
5386 return "zero_width_node";
5389 int zero_width_node::force_tprint()
5394 int zero_width_node::is_tag()
5399 int italic_corrected_node::same(node
*nd
)
5401 return (x
== ((italic_corrected_node
*)nd
)->x
5402 && same_node(n
, ((italic_corrected_node
*)nd
)->n
));
5405 const char *italic_corrected_node::type()
5407 return "italic_corrected_node";
5410 int italic_corrected_node::force_tprint()
5415 int italic_corrected_node::is_tag()
5420 left_italic_corrected_node::left_italic_corrected_node(node
*xx
)
5425 left_italic_corrected_node::left_italic_corrected_node(statem
*s
, int pop
,
5427 : node(xx
, s
, pop
), n(0)
5431 left_italic_corrected_node::~left_italic_corrected_node()
5436 node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
5439 hunits lic
= gn
->left_italic_correction();
5440 if (!lic
.is_zero()) {
5447 node
*nd
= n
->merge_glyph_node(gn
);
5450 x
= n
->left_italic_correction();
5457 node
*left_italic_corrected_node::copy()
5459 left_italic_corrected_node
*nd
=
5460 new left_italic_corrected_node(state
, div_nest_level
);
5468 void left_italic_corrected_node::tprint(troff_output_file
*out
)
5476 const char *left_italic_corrected_node::type()
5478 return "left_italic_corrected_node";
5481 int left_italic_corrected_node::force_tprint()
5486 int left_italic_corrected_node::is_tag()
5491 int left_italic_corrected_node::same(node
*nd
)
5493 return (x
== ((left_italic_corrected_node
*)nd
)->x
5494 && same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
5497 void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
5500 n
->ascii_print(out
);
5503 hunits
left_italic_corrected_node::width()
5505 return n
? n
->width() + x
: H0
;
5508 void left_italic_corrected_node::vertical_extent(vunits
*minimum
,
5512 n
->vertical_extent(minimum
, maximum
);
5514 node::vertical_extent(minimum
, maximum
);
5517 hunits
left_italic_corrected_node::skew()
5519 return n
? n
->skew() + x
/2 : H0
;
5522 hunits
left_italic_corrected_node::subscript_correction()
5524 return n
? n
->subscript_correction() : H0
;
5527 hunits
left_italic_corrected_node::italic_correction()
5529 return n
? n
->italic_correction() : H0
;
5532 int left_italic_corrected_node::ends_sentence()
5534 return n
? n
->ends_sentence() : 0;
5537 int left_italic_corrected_node::overlaps_horizontally()
5539 return n
? n
->overlaps_horizontally() : 0;
5542 int left_italic_corrected_node::overlaps_vertically()
5544 return n
? n
->overlaps_vertically() : 0;
5547 node
*left_italic_corrected_node::last_char_node()
5549 return n
? n
->last_char_node() : 0;
5552 tfont
*left_italic_corrected_node::get_tfont()
5554 return n
? n
->get_tfont() : 0;
5557 hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
5560 return n
->get_hyphenation_type();
5562 return HYPHEN_MIDDLE
;
5565 hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
,
5568 return n
? n
->get_hyphen_list(tail
, count
) : tail
;
5571 node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
5574 nd
= new left_italic_corrected_node(state
, div_nest_level
, nd
);
5575 nd
= n
->add_self(nd
, p
);
5586 int left_italic_corrected_node::character_type()
5588 return n
? n
->character_type() : 0;
5591 int overstrike_node::same(node
*nd
)
5593 return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
5596 const char *overstrike_node::type()
5598 return "overstrike_node";
5601 int overstrike_node::force_tprint()
5606 int overstrike_node::is_tag()
5611 node
*overstrike_node::add_self(node
*n
, hyphen_list
**p
)
5614 hyphen_list
*pp
= *p
;
5620 hyphen_list
*overstrike_node::get_hyphen_list(hyphen_list
*tail
, int *)
5622 return new hyphen_list(0, tail
);
5625 int bracket_node::same(node
*nd
)
5627 return same_node_list(list
, ((bracket_node
*)nd
)->list
);
5630 const char *bracket_node::type()
5632 return "bracket_node";
5635 int bracket_node::force_tprint()
5640 int bracket_node::is_tag()
5645 int composite_node::same(node
*nd
)
5647 return ci
== ((composite_node
*)nd
)->ci
5648 && same_node_list(n
, ((composite_node
*)nd
)->n
);
5651 const char *composite_node::type()
5653 return "composite_node";
5656 int composite_node::force_tprint()
5661 int composite_node::is_tag()
5666 int glyph_node::same(node
*nd
)
5668 return ci
== ((glyph_node
*)nd
)->ci
5669 && tf
== ((glyph_node
*)nd
)->tf
5670 && gcol
== ((glyph_node
*)nd
)->gcol
5671 && fcol
== ((glyph_node
*)nd
)->fcol
;
5674 const char *glyph_node::type()
5676 return "glyph_node";
5679 int glyph_node::force_tprint()
5684 int glyph_node::is_tag()
5689 int ligature_node::same(node
*nd
)
5691 return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
5692 && same_node(n2
, ((ligature_node
*)nd
)->n2
)
5693 && glyph_node::same(nd
));
5696 const char *ligature_node::type()
5698 return "ligature_node";
5701 int ligature_node::force_tprint()
5706 int ligature_node::is_tag()
5711 int kern_pair_node::same(node
*nd
)
5713 return (amount
== ((kern_pair_node
*)nd
)->amount
5714 && same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
5715 && same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
5718 const char *kern_pair_node::type()
5720 return "kern_pair_node";
5723 int kern_pair_node::force_tprint()
5728 int kern_pair_node::is_tag()
5733 int dbreak_node::same(node
*nd
)
5735 return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
5736 && same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
5737 && same_node_list(post
, ((dbreak_node
*)nd
)->post
));
5740 const char *dbreak_node::type()
5742 return "dbreak_node";
5745 int dbreak_node::force_tprint()
5750 int dbreak_node::is_tag()
5755 int break_char_node::same(node
*nd
)
5757 return break_code
== ((break_char_node
*)nd
)->break_code
5758 && col
== ((break_char_node
*)nd
)->col
5759 && same_node(ch
, ((break_char_node
*)nd
)->ch
);
5762 const char *break_char_node::type()
5764 return "break_char_node";
5767 int break_char_node::force_tprint()
5772 int break_char_node::is_tag()
5777 int line_start_node::same(node
* /*nd*/)
5782 const char *line_start_node::type()
5784 return "line_start_node";
5787 int line_start_node::force_tprint()
5792 int line_start_node::is_tag()
5797 int space_node::same(node
*nd
)
5799 return n
== ((space_node
*)nd
)->n
5800 && set
== ((space_node
*)nd
)->set
5801 && col
== ((space_node
*)nd
)->col
;
5804 const char *space_node::type()
5806 return "space_node";
5809 int word_space_node::same(node
*nd
)
5811 return n
== ((word_space_node
*)nd
)->n
5812 && set
== ((word_space_node
*)nd
)->set
5813 && col
== ((word_space_node
*)nd
)->col
;
5816 const char *word_space_node::type()
5818 return "word_space_node";
5821 int word_space_node::force_tprint()
5826 int word_space_node::is_tag()
5831 void unbreakable_space_node::tprint(troff_output_file
*out
)
5833 out
->fill_color(col
);
5835 // we emit the space width as a negative glyph index
5839 out
->put(-n
.to_units());
5845 int unbreakable_space_node::same(node
*nd
)
5847 return n
== ((unbreakable_space_node
*)nd
)->n
5848 && set
== ((unbreakable_space_node
*)nd
)->set
5849 && col
== ((unbreakable_space_node
*)nd
)->col
;
5852 const char *unbreakable_space_node::type()
5854 return "unbreakable_space_node";
5857 node
*unbreakable_space_node::add_self(node
*nd
, hyphen_list
**p
)
5860 hyphen_list
*pp
= *p
;
5866 hyphen_list
*unbreakable_space_node::get_hyphen_list(hyphen_list
*tail
, int *)
5868 return new hyphen_list(0, tail
);
5871 int diverted_space_node::same(node
*nd
)
5873 return n
== ((diverted_space_node
*)nd
)->n
;
5876 const char *diverted_space_node::type()
5878 return "diverted_space_node";
5881 int diverted_space_node::force_tprint()
5886 int diverted_space_node::is_tag()
5891 int diverted_copy_file_node::same(node
*nd
)
5893 return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
5896 const char *diverted_copy_file_node::type()
5898 return "diverted_copy_file_node";
5901 int diverted_copy_file_node::force_tprint()
5906 int diverted_copy_file_node::is_tag()
5911 // Grow the font_table so that its size is > n.
5913 static void grow_font_table(int n
)
5915 assert(n
>= font_table_size
);
5916 font_info
**old_font_table
= font_table
;
5917 int old_font_table_size
= font_table_size
;
5918 font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
5919 if (font_table_size
<= n
)
5920 font_table_size
= n
+ 10;
5921 font_table
= new font_info
*[font_table_size
];
5922 if (old_font_table_size
)
5923 memcpy(font_table
, old_font_table
,
5924 old_font_table_size
*sizeof(font_info
*));
5925 a_delete old_font_table
;
5926 for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
5930 dictionary
font_translation_dictionary(17);
5932 static symbol
get_font_translation(symbol nm
)
5934 void *p
= font_translation_dictionary
.lookup(nm
);
5935 return p
? symbol((char *)p
) : nm
;
5938 dictionary
font_dictionary(50);
5940 static int mount_font_no_translate(int n
, symbol name
, symbol external_name
,
5944 // We store the address of this char in font_dictionary to indicate
5945 // that we've previously tried to mount the font and failed.
5948 void *p
= font_dictionary
.lookup(external_name
);
5951 fm
= font::load_font(external_name
.contents(), ¬_found
, check_only
);
5956 warning(WARN_FONT
, "can't find font `%1'", external_name
.contents());
5957 (void)font_dictionary
.lookup(external_name
, &a_char
);
5960 (void)font_dictionary
.lookup(name
, fm
);
5962 else if (p
== &a_char
) {
5964 error("invalid font `%1'", external_name
.contents());
5972 if (n
>= font_table_size
) {
5973 if (n
- font_table_size
> 1000) {
5974 error("font position too much larger than first unused position");
5979 else if (font_table
[n
] != 0)
5980 delete font_table
[n
];
5981 font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
5982 font_family::invalidate_fontno(n
);
5986 int mount_font(int n
, symbol name
, symbol external_name
)
5989 name
= get_font_translation(name
);
5990 if (external_name
.is_null())
5991 external_name
= name
;
5993 external_name
= get_font_translation(external_name
);
5994 return mount_font_no_translate(n
, name
, external_name
);
5997 int check_font(symbol fam
, symbol name
)
5999 if (check_style(name
))
6000 name
= concat(fam
, name
);
6001 return mount_font_no_translate(0, name
, name
, 1);
6004 int check_style(symbol s
)
6006 int i
= symbol_fontno(s
);
6007 return i
< 0 ? 0 : font_table
[i
]->is_style();
6010 void mount_style(int n
, symbol name
)
6013 if (n
>= font_table_size
) {
6014 if (n
- font_table_size
> 1000) {
6015 error("font position too much larger than first unused position");
6020 else if (font_table
[n
] != 0)
6021 delete font_table
[n
];
6022 font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
6023 font_family::invalidate_fontno(n
);
6026 /* global functions */
6028 void font_translate()
6030 symbol from
= get_name(1);
6031 if (!from
.is_null()) {
6032 symbol to
= get_name();
6033 if (to
.is_null() || from
== to
)
6034 font_translation_dictionary
.remove(from
);
6036 (void)font_translation_dictionary
.lookup(from
, (void *)to
.contents());
6041 void font_position()
6044 if (get_integer(&n
)) {
6046 error("negative font position");
6048 symbol internal_name
= get_name(1);
6049 if (!internal_name
.is_null()) {
6050 symbol external_name
= get_long_name();
6051 mount_font(n
, internal_name
, external_name
); // ignore error
6058 font_family::font_family(symbol s
)
6059 : map_size(10), nm(s
)
6061 map
= new int[map_size
];
6062 for (int i
= 0; i
< map_size
; i
++)
6066 font_family::~font_family()
6071 int font_family::make_definite(int i
)
6074 if (i
< map_size
&& map
[i
] >= 0)
6077 if (i
< font_table_size
&& font_table
[i
] != 0) {
6078 if (i
>= map_size
) {
6079 int old_map_size
= map_size
;
6085 map
= new int[map_size
];
6086 memcpy(map
, old_map
, old_map_size
*sizeof(int));
6088 for (int j
= old_map_size
; j
< map_size
; j
++)
6091 if (font_table
[i
]->is_style()) {
6092 symbol sty
= font_table
[i
]->get_name();
6093 symbol f
= concat(nm
, sty
);
6095 // don't use symbol_fontno, because that might return a style
6096 // and because we don't want to translate the name
6097 for (n
= 0; n
< font_table_size
; n
++)
6098 if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
6099 && !font_table
[n
]->is_style())
6101 if (n
>= font_table_size
) {
6102 n
= next_available_font_position();
6103 if (!mount_font_no_translate(n
, f
, f
))
6119 dictionary
family_dictionary(5);
6121 font_family
*lookup_family(symbol nm
)
6123 font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
6125 f
= new font_family(nm
);
6126 (void)family_dictionary
.lookup(nm
, f
);
6131 void font_family::invalidate_fontno(int n
)
6133 assert(n
>= 0 && n
< font_table_size
);
6134 dictionary_iterator
iter(family_dictionary
);
6137 while (iter
.get(&nam
, (void **)&fam
)) {
6138 int mapsize
= fam
->map_size
;
6141 for (int i
= 0; i
< mapsize
; i
++)
6142 if (fam
->map
[i
] == n
)
6150 if (get_integer(&n
)) {
6152 error("negative font position");
6154 symbol internal_name
= get_name(1);
6155 if (!internal_name
.is_null())
6156 mount_style(n
, internal_name
);
6162 static int get_fontno()
6166 if (tok
.delimiter()) {
6167 symbol s
= get_name(1);
6169 n
= symbol_fontno(s
);
6171 n
= next_available_font_position();
6172 if (!mount_font(n
, s
))
6175 return curenv
->get_family()->make_definite(n
);
6178 else if (get_integer(&n
)) {
6179 if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
6180 error("bad font number");
6182 return curenv
->get_family()->make_definite(n
);
6187 static int underline_fontno
= 2;
6189 void underline_font()
6191 int n
= get_fontno();
6193 underline_fontno
= n
;
6197 int get_underline_fontno()
6199 return underline_fontno
;
6202 void define_font_special_character()
6204 int n
= get_fontno();
6209 symbol f
= font_table
[n
]->get_name();
6210 do_define_character(CHAR_FONT_SPECIAL
, f
.contents());
6213 void remove_font_special_character()
6215 int n
= get_fontno();
6220 symbol f
= font_table
[n
]->get_name();
6221 while (!tok
.newline() && !tok
.eof()) {
6222 if (!tok
.space() && !tok
.tab()) {
6223 charinfo
*s
= tok
.get_char(1);
6224 string
gl(f
.contents());
6226 gl
+= s
->nm
.contents();
6228 charinfo
*ci
= get_charinfo(symbol(gl
.contents()));
6231 macro
*m
= ci
->set_macro(0);
6240 static void read_special_fonts(special_font_list
**sp
)
6242 special_font_list
*s
= *sp
;
6245 special_font_list
*tem
= s
;
6249 special_font_list
**p
= sp
;
6251 int i
= get_fontno();
6253 special_font_list
*tem
= new special_font_list
;
6262 void font_special_request()
6264 int n
= get_fontno();
6266 read_special_fonts(&font_table
[n
]->sf
);
6270 void special_request()
6272 read_special_fonts(&global_special_fonts
);
6276 void font_zoom_request()
6278 int n
= get_fontno();
6280 if (font_table
[n
]->is_style())
6281 warning(WARN_FONT
, "can't set zoom factor for a style");
6284 if (has_arg() && get_integer(&zoom
)) {
6286 warning(WARN_FONT
, "can't use negative zoom factor");
6288 font_table
[n
]->set_zoom(zoom
);
6291 font_table
[n
]->set_zoom(0);
6297 int next_available_font_position()
6300 for (i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
6305 int symbol_fontno(symbol s
)
6307 s
= get_font_translation(s
);
6308 for (int i
= 0; i
< font_table_size
; i
++)
6309 if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
6314 int is_good_fontno(int n
)
6316 return n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0;
6319 int get_bold_fontno(int n
)
6321 if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
6323 if (font_table
[n
]->get_bold(&offset
))
6324 return offset
.to_units() + 1;
6332 hunits
env_digit_width(environment
*env
)
6334 node
*n
= make_glyph_node(charset_table
['0'], env
);
6336 hunits x
= n
->width();
6344 hunits
env_space_width(environment
*env
)
6346 int fn
= env_definite_font(env
);
6347 font_size fs
= env
->get_font_size();
6348 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6349 return scale(fs
.to_units()/3, env
->get_space_size(), 12);
6351 return font_table
[fn
]->get_space_width(fs
, env
->get_space_size());
6354 hunits
env_sentence_space_width(environment
*env
)
6356 int fn
= env_definite_font(env
);
6357 font_size fs
= env
->get_font_size();
6358 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6359 return scale(fs
.to_units()/3, env
->get_sentence_space_size(), 12);
6361 return font_table
[fn
]->get_space_width(fs
, env
->get_sentence_space_size());
6364 hunits
env_half_narrow_space_width(environment
*env
)
6366 int fn
= env_definite_font(env
);
6367 font_size fs
= env
->get_font_size();
6368 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6371 return font_table
[fn
]->get_half_narrow_space_width(fs
);
6374 hunits
env_narrow_space_width(environment
*env
)
6376 int fn
= env_definite_font(env
);
6377 font_size fs
= env
->get_font_size();
6378 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
6381 return font_table
[fn
]->get_narrow_space_width(fs
);
6386 int n
= get_fontno();
6389 if (tok
.delimiter()) {
6390 int f
= get_fontno();
6393 if (has_arg() && get_number(&offset
, 'u') && offset
>= 1)
6394 font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
6396 font_table
[f
]->conditional_unbold(n
);
6401 if (get_number(&offset
, 'u') && offset
>= 1)
6402 font_table
[n
]->set_bold(hunits(offset
- 1));
6404 font_table
[n
]->unbold();
6408 font_table
[n
]->unbold();
6413 track_kerning_function::track_kerning_function() : non_zero(0)
6417 track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
6418 int max_s
, hunits max_a
)
6419 : non_zero(1), min_size(min_s
), min_amount(min_a
), max_size(max_s
),
6424 int track_kerning_function::operator==(const track_kerning_function
&tk
)
6428 && min_size
== tk
.min_size
6429 && min_amount
== tk
.min_amount
6430 && max_size
== tk
.max_size
6431 && max_amount
== tk
.max_amount
);
6433 return !tk
.non_zero
;
6436 int track_kerning_function::operator!=(const track_kerning_function
&tk
)
6439 return (!tk
.non_zero
6440 || min_size
!= tk
.min_size
6441 || min_amount
!= tk
.min_amount
6442 || max_size
!= tk
.max_size
6443 || max_amount
!= tk
.max_amount
);
6448 hunits
track_kerning_function::compute(int size
)
6451 if (max_size
<= min_size
)
6453 else if (size
<= min_size
)
6455 else if (size
>= max_size
)
6458 return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
6459 + scale(min_amount
, max_size
- size
, max_size
- min_size
));
6467 int n
= get_fontno();
6470 hunits min_a
, max_a
;
6472 && get_number(&min_s
, 'z')
6473 && get_hunits(&min_a
, 'p')
6474 && get_number(&max_s
, 'z')
6475 && get_hunits(&max_a
, 'p')) {
6476 track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
6477 font_table
[n
]->set_track_kern(tk
);
6480 track_kerning_function tk
;
6481 font_table
[n
]->set_track_kern(tk
);
6487 void constant_space()
6489 int n
= get_fontno();
6492 if (!has_arg() || !get_integer(&x
))
6493 font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
6495 if (!has_arg() || !get_number(&y
, 'z'))
6496 font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
6498 font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
6510 if (has_arg() && get_integer(&lig
) && lig
>= 0 && lig
<= 2)
6511 global_ligature_mode
= lig
;
6513 global_ligature_mode
= 1;
6520 if (has_arg() && get_integer(&k
))
6521 global_kern_mode
= k
!= 0;
6523 global_kern_mode
= 1;
6527 void set_soft_hyphen_char()
6529 soft_hyphen_char
= get_optional_char();
6530 if (!soft_hyphen_char
)
6531 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);
6537 if (suppress_output_flag
)
6538 the_output
= new suppress_output_file
;
6539 else if (ascii_output_flag
)
6540 the_output
= new ascii_output_file
;
6542 the_output
= new troff_output_file
;
6545 class next_available_font_position_reg
6549 const char *get_string();
6552 const char *next_available_font_position_reg::get_string()
6554 return i_to_a(next_available_font_position());
6561 const char *get_string();
6564 const char *printing_reg::get_string()
6567 return the_output
->is_printing() ? "1" : "0";
6572 void init_node_requests() // TODO move static inits in here?!!
6574 init_request("bd", bold_font
);
6575 init_request("cs", constant_space
);
6576 init_request("fp", font_position
);
6577 init_request("fschar", define_font_special_character
);
6578 init_request("fspecial", font_special_request
);
6579 init_request("fzoom", font_zoom_request
);
6580 init_request("ftr", font_translate
);
6581 init_request("kern", kern_request
);
6582 init_request("lg", ligature
);
6583 init_request("rfschar", remove_font_special_character
);
6584 init_request("shc", set_soft_hyphen_char
);
6585 init_request("special", special_request
);
6586 init_request("sty", style
);
6587 init_request("tkf", track_kern
);
6588 init_request("uf", underline_font
);
6589 number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
6590 number_reg_dictionary
.define(".kern",
6591 new constant_int_reg(&global_kern_mode
));
6592 number_reg_dictionary
.define(".lg",
6593 new constant_int_reg(&global_ligature_mode
));
6594 number_reg_dictionary
.define(".P", new printing_reg
);
6595 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);