/* Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
You should have received a copy of the GNU General Public License along
with groff; see the file LICENSE. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
symbol
HYPHEN_SYMBOL("hy");
enum constant_space_type
{
struct special_font_list
{
special_font_list
*global_special_fonts
;
static int global_ligature_mode
= 1;
static int global_kern_mode
= 1;
class track_kerning_function
{
track_kerning_function();
track_kerning_function(units
, hunits
, units
, hunits
);
int operator==(const track_kerning_function
&);
int operator!=(const track_kerning_function
&);
hunits
compute(int point_size
);
// embolden fontno when this is the current font
struct conditional_bold
{
conditional_bold(int, hunits
, conditional_bold
* = 0);
track_kerning_function track_kern
;
constant_space_type is_constant_spaced
;
conditional_bold
*cond_bold_list
;
font_info(symbol nm
, int n
, symbol enm
, font
*f
);
int contains(charinfo
*);
void set_conditional_bold(int, hunits
);
void conditional_unbold(int);
void set_track_kern(track_kerning_function
&);
void set_constant_space(constant_space_type
, units
= 0);
tfont
*get_tfont(font_size
, int, int, int);
hunits
get_space_width(font_size
);
hunits
get_narrow_space_width(font_size
);
hunits
get_half_narrow_space_width(font_size
);
hunits track_kern
; // add this to the width
hunits constant_space_width
;
tfont_spec(symbol nm
, int pos
, font
*, font_size
, int, int);
int operator==(const tfont_spec
&);
friend tfont
*font_info::get_tfont(font_size fs
, int, int, int);
class tfont
: public tfont_spec
{
static tfont
*tfont_list
;
int contains(charinfo
*);
hunits
get_width(charinfo
*c
);
int get_constant_space(hunits
*);
charinfo
*get_lig(charinfo
*c1
, charinfo
*c2
);
int get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
);
int get_input_position();
int get_character_type(charinfo
*);
vunits
get_char_height(charinfo
*);
vunits
get_char_depth(charinfo
*);
hunits
get_char_skew(charinfo
*);
hunits
get_italic_correction(charinfo
*);
hunits
get_left_italic_correction(charinfo
*);
hunits
get_subscript_correction(charinfo
*);
friend tfont
*make_tfont(tfont_spec
&);
inline int env_definite_font(environment
*env
)
return env
->get_family()->make_definite(env
->get_font());
static void invalidate_fontno(int n
);
/* font_info functions */
static font_info
**font_table
= 0;
static int font_table_size
= 0;
font_info::font_info(symbol nm
, int n
, symbol enm
, font
*f
)
: internal_name(nm
), external_name(enm
), fm(f
), number(n
),
is_constant_spaced(CONSTANT_SPACE_NONE
),
sf(0), is_bold(0), cond_bold_list(0),
last_ligature_mode(1), last_kern_mode(1),
last_tfont(0), last_size(0)
inline int font_info::contains(charinfo
*ci
)
return fm
!= 0 && fm
->contains(ci
->get_index());
inline int font_info::is_special()
return fm
!= 0 && fm
->is_special();
inline int font_info::is_style()
// this is the current_font, fontno is where we found the character,
// presumably a special font
tfont
*font_info::get_tfont(font_size fs
, int height
, int slant
, int fontno
)
if (last_tfont
== 0 || fs
!= last_size
|| height
!= last_height
|| slant
!= last_slant
|| global_ligature_mode
!= last_ligature_mode
|| global_kern_mode
!= last_kern_mode
font_info
*f
= font_table
[fontno
];
tfont_spec
spec(f
->external_name
, f
->number
, f
->fm
, fs
, height
, slant
);
for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
if (p
->fontno
== fontno
) {
spec
.bold_offset
= p
->offset
;
if (!spec
.is_bold
&& is_bold
) {
spec
.bold_offset
= bold_offset
;
spec
.track_kern
= track_kern
.compute(fs
.to_scaled_points());
spec
.ligature_mode
= global_ligature_mode
;
spec
.kern_mode
= global_kern_mode
;
switch (is_constant_spaced
) {
case CONSTANT_SPACE_NONE
:
case CONSTANT_SPACE_ABSOLUTE
:
spec
.is_constant_spaced
= 1;
spec
.constant_space_width
= constant_space
;
case CONSTANT_SPACE_RELATIVE
:
spec
.is_constant_spaced
= 1;
spec
.constant_space_width
= scale(constant_space
*fs
.to_scaled_points(),
last_tfont
= make_tfont(spec
);
last_ligature_mode
= global_ligature_mode
;
last_kern_mode
= global_kern_mode
;
int font_info::get_bold(hunits
*res
)
void font_info::set_bold(hunits offset
)
if (!is_bold
|| offset
!= bold_offset
) {
void font_info::set_conditional_bold(int fontno
, hunits offset
)
for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
if (p
->fontno
== fontno
) {
if (offset
!= p
->offset
) {
cond_bold_list
= new conditional_bold(fontno
, offset
, cond_bold_list
);
conditional_bold::conditional_bold(int f
, hunits h
, conditional_bold
*x
)
: fontno(f
), offset(h
), next(x
)
void font_info::conditional_unbold(int fontno
)
for (conditional_bold
**p
= &cond_bold_list
; *p
; p
= &(*p
)->next
)
if ((*p
)->fontno
== fontno
) {
conditional_bold
*tem
= *p
;
void font_info::set_constant_space(constant_space_type type
, units x
)
if (type
!= is_constant_spaced
|| (type
!= CONSTANT_SPACE_NONE
&& x
!= constant_space
)) {
is_constant_spaced
= type
;
void font_info::set_track_kern(track_kerning_function
&tk
)
int font_info::is_named(symbol s
)
return internal_name
== s
;
symbol
font_info::get_name()
hunits
font_info::get_space_width(font_size fs
)
return hunits(fm
->get_space_width(fs
.to_scaled_points()));
hunits
font_info::get_narrow_space_width(font_size fs
)
charinfo
*ci
= get_charinfo(symbol("|"));
if (fm
->contains(ci
->get_index()))
return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
return hunits(fs
.to_units()/6);
hunits
font_info::get_half_narrow_space_width(font_size fs
)
charinfo
*ci
= get_charinfo(symbol("^"));
if (fm
->contains(ci
->get_index()))
return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
return hunits(fs
.to_units()/12);
tfont_spec::tfont_spec(symbol nm
, int n
, font
*f
,
font_size s
, int h
, int sl
)
: name(nm
), input_position(n
), fm(f
), size(s
),
is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
if (height
== size
.to_scaled_points())
int tfont_spec::operator==(const tfont_spec
&spec
)
&& input_position
== spec
.input_position
? (spec
.is_bold
&& bold_offset
== spec
.bold_offset
)
&& track_kern
== spec
.track_kern
? (spec
.is_constant_spaced
&& constant_space_width
== spec
.constant_space_width
)
: !spec
.is_constant_spaced
)
&& ligature_mode
== spec
.ligature_mode
&& kern_mode
== spec
.kern_mode
)
tfont_spec
tfont_spec::plain()
return tfont_spec(name
, input_position
, fm
, size
, height
, slant
);
hunits
tfont::get_width(charinfo
*c
)
return constant_space_width
;
return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
+ track_kern
+ bold_offset
);
return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points())) + track_kern
);
vunits
tfont::get_char_height(charinfo
*c
)
vunits v
= fm
->get_height(c
->get_index(), size
.to_scaled_points());
if (height
!= 0 && height
!= size
.to_scaled_points())
return scale(v
, height
, size
.to_scaled_points());
vunits
tfont::get_char_depth(charinfo
*c
)
vunits v
= fm
->get_depth(c
->get_index(), size
.to_scaled_points());
if (height
!= 0 && height
!= size
.to_scaled_points())
return scale(v
, height
, size
.to_scaled_points());
hunits
tfont::get_char_skew(charinfo
*c
)
return hunits(fm
->get_skew(c
->get_index(), size
.to_scaled_points(), slant
));
hunits
tfont::get_italic_correction(charinfo
*c
)
return hunits(fm
->get_italic_correction(c
->get_index(), size
.to_scaled_points()));
hunits
tfont::get_left_italic_correction(charinfo
*c
)
return hunits(fm
->get_left_italic_correction(c
->get_index(),
size
.to_scaled_points()));
hunits
tfont::get_subscript_correction(charinfo
*c
)
return hunits(fm
->get_subscript_correction(c
->get_index(),
size
.to_scaled_points()));
inline int tfont::get_input_position()
inline int tfont::contains(charinfo
*ci
)
return fm
->contains(ci
->get_index());
inline int tfont::get_character_type(charinfo
*ci
)
return fm
->get_character_type(ci
->get_index());
inline int tfont::get_bold(hunits
*res
)
inline int tfont::get_constant_space(hunits
*res
)
if (is_constant_spaced
) {
*res
= constant_space_width
;
inline hunits
tfont::get_track_kern()
inline tfont
*tfont::get_plain()
inline font_size
tfont::get_size()
inline symbol
tfont::get_name()
inline int tfont::get_height()
inline int tfont::get_slant()
charinfo
*tfont::get_lig(charinfo
*c1
, charinfo
*c2
)
if (c1
->get_ascii_code() == 'f') {
switch (c2
->get_ascii_code()) {
if (fm
->has_ligature(font::LIG_ff
))
ci
= get_charinfo(SYMBOL_ff
);
if (fm
->has_ligature(font::LIG_fi
))
ci
= get_charinfo(SYMBOL_fi
);
if (fm
->has_ligature(font::LIG_fl
))
ci
= get_charinfo(SYMBOL_fl
);
else if (ligature_mode
!= 2 && c1
->nm
== SYMBOL_ff
) {
switch (c2
->get_ascii_code()) {
if (fm
->has_ligature(font::LIG_ffi
))
ci
= get_charinfo(SYMBOL_Fi
);
if (fm
->has_ligature(font::LIG_ffl
))
ci
= get_charinfo(SYMBOL_Fl
);
if (ci
!= 0 && fm
->contains(ci
->get_index()))
inline int tfont::get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
)
int n
= fm
->get_kern(c1
->get_index(),
size
.to_scaled_points());
tfont
*make_tfont(tfont_spec
&spec
)
for (tfont
*p
= tfont::tfont_list
; p
; p
= p
->next
)
tfont
*tfont::tfont_list
= 0;
tfont::tfont(tfont_spec
&spec
) : tfont_spec(spec
)
tfont_spec plain_spec
= plain();
for (tfont
*p
= tfont_list
; p
; p
= p
->next
)
plain_version
= new tfont(plain_spec
);
class real_output_file
: public output_file
{
virtual void really_transparent_char(unsigned char) = 0;
virtual void really_print_line(hunits x
, vunits y
, node
*n
,
vunits before
, vunits after
) = 0;
virtual void really_begin_page(int pageno
, vunits page_length
) = 0;
virtual void really_copy_file(hunits x
, vunits y
, const char *filename
);
void transparent_char(unsigned char);
void print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
);
void begin_page(int pageno
, vunits page_length
);
void copy_file(hunits x
, vunits y
, const char *filename
);
class suppress_output_file
: public real_output_file
{
void really_transparent_char(unsigned char);
void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
);
void really_begin_page(int pageno
, vunits page_length
);
class ascii_output_file
: public real_output_file
{
void really_transparent_char(unsigned char);
void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
);
void really_begin_page(int pageno
, vunits page_length
);
void outc(unsigned char c
);
void outs(const char *s
);
void ascii_output_file::outc(unsigned char c
)
void ascii_output_file::outs(const char *s
)
class troff_output_file
: public real_output_file
{
enum { TBUF_SIZE
= 256 };
void put(unsigned char c
);
void set_font(tfont
*tf
);
void put_char(charinfo
*ci
, tfont
*tf
);
void put_char_width(charinfo
*ci
, tfont
*tf
, hunits w
, hunits k
);
void moveto(hunits
, vunits
);
void special_char(unsigned char c
);
void really_transparent_char(unsigned char c
);
void really_print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
);
void really_begin_page(int pageno
, vunits page_length
);
void really_copy_file(hunits x
, vunits y
, const char *filename
);
void draw(char, hvpair
*, int, font_size
);
int get_hpos() { return hpos
; }
int get_vpos() { return vpos
; }
static void put_string(const char *s
, FILE *fp
)
inline void troff_output_file::put(char c
)
inline void troff_output_file::put(unsigned char c
)
inline void troff_output_file::put(const char *s
)
inline void troff_output_file::put(int i
)
void troff_output_file::start_special()
void troff_output_file::special_char(unsigned char c
)
void troff_output_file::end_special()
inline void troff_output_file::moveto(hunits h
, vunits v
)
void troff_output_file::really_print_line(hunits x
, vunits y
, node
*n
,
vunits before
, vunits after
)
// This ensures that transparent throughput will have a more predictable
inline void troff_output_file::word_marker()
inline void troff_output_file::right(hunits n
)
inline void troff_output_file::down(vunits n
)
void troff_output_file::do_motion()
if (hpos
!= output_hpos
) {
units n
= hpos
- output_hpos
;
if (vpos
!= output_vpos
) {
units n
= vpos
- output_vpos
;
void troff_output_file::flush_tbuf()
for (int i
= 0; i
< tbuf_len
; i
++)
void troff_output_file::put_char_width(charinfo
*ci
, tfont
*tf
, hunits w
,
if (tf
!= current_tfont
) {
char c
= ci
->get_ascii_code();
int n
= ci
->get_number();
const char *s
= ci
->nm
.contents();
hpos
+= w
.to_units() + kk
;
else if (tcommand_flag
) {
if (tbuf_len
> 0 && hpos
== output_hpos
&& vpos
== output_vpos
&& tbuf_len
< TBUF_SIZE
) {
output_hpos
+= w
.to_units() + kk
;
output_hpos
+= w
.to_units() + kk
;
int n
= hpos
- output_hpos
;
if (vpos
== output_vpos
&& n
> 0 && n
< 100 && !force_motion
) {
hpos
+= w
.to_units() + kk
;
void troff_output_file::put_char(charinfo
*ci
, tfont
*tf
)
char c
= ci
->get_ascii_code();
int n
= ci
->get_number();
const char *s
= ci
->nm
.contents();
int n
= hpos
- output_hpos
;
if (vpos
== output_vpos
&& n
> 0 && n
< 100) {
void troff_output_file::set_font(tfont
*tf
)
int n
= tf
->get_input_position();
symbol nm
= tf
->get_name();
if (n
>= nfont_positions
|| font_position
[n
] != nm
) {
if (n
>= nfont_positions
) {
int old_nfont_positions
= nfont_positions
;
symbol
*old_font_position
= font_position
;
if (nfont_positions
<= n
)
nfont_positions
= n
+ 10;
font_position
= new symbol
[nfont_positions
];
memcpy(font_position
, old_font_position
,
old_nfont_positions
*sizeof(symbol
));
delete old_font_position
;
if (current_font_number
!= n
) {
int size
= tf
->get_size().to_scaled_points();
if (current_size
!= size
) {
int slant
= tf
->get_slant();
if (current_slant
!= slant
) {
int height
= tf
->get_height();
if (current_height
!= height
) {
put(height
== 0 ? current_size
: height
);
void troff_output_file::draw(char code
, hvpair
*point
, int npoints
,
int size
= fsize
.to_scaled_points();
if (current_size
!= size
) {
put(point
[0].h
.to_units());
for (i
= 0; i
< npoints
; i
++) {
put(point
[i
].h
.to_units());
put(point
[i
].v
.to_units());
for (i
= 0; i
< npoints
; i
++)
output_hpos
+= point
[i
].h
.to_units();
for (i
= 0; i
< npoints
; i
++)
output_vpos
+= point
[i
].v
.to_units();
void troff_output_file::really_begin_page(int pageno
, vunits pl
)
put(page_length
.to_units());
current_font_number
= -1;
for (int i
= 0; i
< nfont_positions
; i
++)
font_position
[i
] = NULL_SYMBOL
;
void troff_output_file::really_copy_file(hunits x
, vunits y
, const char *filename
)
FILE *ifp
= fopen(filename
, "r");
error("can't open `%1': %2", filename
, strerror(errno
));
while ((c
= getc(ifp
)) != EOF
)
current_font_number
= -1;
for (int i
= 0; i
< nfont_positions
; i
++)
font_position
[i
] = NULL_SYMBOL
;
void troff_output_file::really_transparent_char(unsigned char c
)
troff_output_file::~troff_output_file()
put(page_length
.to_units());
troff_output_file::troff_output_file()
: current_height(0), current_slant(0), tbuf_len(0), nfont_positions(10)
font_position
= new symbol
[nfont_positions
];
output_file
*the_output
= 0;
output_file::output_file()
output_file::~output_file()
real_output_file::real_output_file()
if ((fp
= popen(pipe_command
, "w")) != 0) {
error("pipe open failed: %1", strerror(errno
));
real_output_file::~real_output_file()
// To avoid looping, set fp to 0 before calling fatal().
if (ferror(fp
) || fflush(fp
) < 0) {
fatal("error writing output file");
if ((result
& 0x7f) != 0)
error("output process `%1' got fatal signal %2",
pipe_command
, result
& 0x7f);
int exit_status
= (result
>> 8) & 0xff;
error("output process `%1' exited with status %2",
pipe_command
, exit_status
);
else if (fclose(fp
) < 0) {
fatal("error closing output file");
void real_output_file::flush()
fatal("error writing output file");
int real_output_file::is_printing()
void real_output_file::begin_page(int pageno
, vunits page_length
)
printing
= in_output_page_list(pageno
);
really_begin_page(pageno
, page_length
);
void real_output_file::copy_file(hunits x
, vunits y
, const char *filename
)
really_copy_file(x
, y
, filename
);
void real_output_file::transparent_char(unsigned char c
)
really_transparent_char(c
);
void real_output_file::print_line(hunits x
, vunits y
, node
*n
,
vunits before
, vunits after
)
really_print_line(x
, y
, n
, before
, after
);
void real_output_file::really_copy_file(hunits
, vunits
, const char *)
void ascii_output_file::really_transparent_char(unsigned char c
)
void ascii_output_file::really_print_line(hunits
, vunits
, node
*n
, vunits
, vunits
)
void ascii_output_file::really_begin_page(int /*pageno*/, vunits
/*page_length*/)
fputs("<beginning of page>\n", fp
);
ascii_output_file::ascii_output_file()
/* suppress_output_file */
suppress_output_file::suppress_output_file()
void suppress_output_file::really_print_line(hunits
, vunits
, node
*, vunits
, vunits
)
void suppress_output_file::really_begin_page(int pageno
, vunits page_length
)
void suppress_output_file::really_transparent_char(unsigned char c
)
/* glyphs, ligatures, kerns, discretionary breaks */
class glyph_node
: public node
{
static glyph_node
*free_list
;
glyph_node(charinfo
*, tfont
*, hunits
, node
* = 0);
void *operator new(size_t);
void operator delete(void *);
glyph_node(charinfo
*, tfont
*, node
* = 0);
node
*merge_glyph_node(glyph_node
*);
node
*merge_self(node
*);
void vertical_extent(vunits
*, vunits
*);
hunits
subscript_correction();
hunits
italic_correction();
hunits
left_italic_correction();
hyphenation_type
get_hyphenation_type();
void tprint(troff_output_file
*);
void zero_width_tprint(troff_output_file
*);
hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
node
*add_self(node
*, hyphen_list
**);
int overlaps_vertically();
int overlaps_horizontally();
void ascii_print(ascii_output_file
*);
glyph_node
*glyph_node::free_list
= 0;
class ligature_node
: public glyph_node
{
ligature_node(charinfo
*, tfont
*, hunits
, node
*gn1
, node
*gn2
, node
*x
= 0);
void *operator new(size_t);
void operator delete(void *);
ligature_node(charinfo
*, tfont
*, node
*gn1
, node
*gn2
, node
*x
= 0);
node
*add_self(node
*, hyphen_list
**);
hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
void ascii_print(ascii_output_file
*);
class kern_pair_node
: public node
{
kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
= 0);
node
*merge_glyph_node(glyph_node
*);
node
*add_self(node
*, hyphen_list
**);
hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
node
*add_discretionary_hyphen();
hunits
italic_correction();
hunits
subscript_correction();
void tprint(troff_output_file
*);
hyphenation_type
get_hyphenation_type();
void ascii_print(ascii_output_file
*);
class dbreak_node
: public node
{
dbreak_node(node
*n
, node
*p
, node
*x
= 0);
node
*merge_glyph_node(glyph_node
*);
node
*add_discretionary_hyphen();
hunits
italic_correction();
hunits
subscript_correction();
void tprint(troff_output_file
*);
breakpoint
*get_breakpoints(hunits width
, int ns
, breakpoint
*rest
= 0,
void split(int, node
**, node
**);
hyphenation_type
get_hyphenation_type();
void ascii_print(ascii_output_file
*);
void *glyph_node::operator new(size_t n
)
assert(n
== sizeof(glyph_node
));
free_list
= (glyph_node
*)new char[sizeof(glyph_node
)*BLOCK
];
for (int i
= 0; i
< BLOCK
- 1; i
++)
free_list
[i
].next
= free_list
+ i
+ 1;
free_list
[BLOCK
-1].next
= 0;
glyph_node
*p
= free_list
;
free_list
= (glyph_node
*)(free_list
->next
);
void *ligature_node::operator new(size_t n
)
void glyph_node::operator delete(void *p
)
((glyph_node
*)p
)->next
= free_list
;
free_list
= (glyph_node
*)p
;
void ligature_node::operator delete(void *p
)
glyph_node::glyph_node(charinfo
*c
, tfont
*t
, node
*x
)
glyph_node::glyph_node(charinfo
*c
, tfont
*t
, hunits w
, node
*x
)
: ci(c
), tf(t
), wid(w
), node(x
)
return new glyph_node(ci
, tf
, wid
);
return new glyph_node(ci
, tf
);
node
*glyph_node::merge_self(node
*nd
)
return nd
->merge_glyph_node(this);
int glyph_node::character_type()
return tf
->get_character_type(ci
);
node
*glyph_node::add_self(node
*n
, hyphen_list
**p
)
assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
if (n
== 0 || (nn
= n
->merge_glyph_node(this)) == 0) {
nn
= nn
->add_discretionary_hyphen();
int glyph_node::overlaps_horizontally()
return ci
->overlaps_horizontally();
int glyph_node::overlaps_vertically()
return ci
->overlaps_vertically();
return tf
->get_size().to_units();
hyphen_list
*glyph_node::get_hyphen_list(hyphen_list
*tail
)
return new hyphen_list(ci
->get_hyphenation_code(), tail
);
tfont
*glyph_node::get_tfont()
node
*node::merge_glyph_node(glyph_node
* /*gn*/)
node
*glyph_node::merge_glyph_node(glyph_node
*gn
)
if ((lig
= tf
->get_lig(ci
, gn
->ci
)) != 0) {
return new ligature_node(lig
, tf
, this, gn
, next1
);
if (tf
->get_kern(ci
, gn
->ci
, &kern
)) {
return new kern_pair_node(kern
, this, gn
, next1
);
hunits
glyph_node::width()
return tf
->get_width(ci
);
node
*glyph_node::last_char_node()
void glyph_node::vertical_extent(vunits
*min
, vunits
*max
)
*min
= -tf
->get_char_height(ci
);
*max
= tf
->get_char_depth(ci
);
hunits
glyph_node::skew()
return tf
->get_char_skew(ci
);
hunits
glyph_node::subscript_correction()
return tf
->get_subscript_correction(ci
);
hunits
glyph_node::italic_correction()
return tf
->get_italic_correction(ci
);
hunits
glyph_node::left_italic_correction()
return tf
->get_left_italic_correction(ci
);
hyphenation_type
glyph_node::get_hyphenation_type()
int glyph_node::ends_sentence()
else if (ci
->transparent())
void glyph_node::ascii_print(ascii_output_file
*ascii
)
unsigned char c
= ci
->get_ascii_code();
ascii
->outs(ci
->nm
.contents());
ligature_node::ligature_node(charinfo
*c
, tfont
*t
,
node
*gn1
, node
*gn2
, node
*x
)
: glyph_node(c
, t
, x
), n1(gn1
), n2(gn2
)
ligature_node::ligature_node(charinfo
*c
, tfont
*t
, hunits w
,
node
*gn1
, node
*gn2
, node
*x
)
: glyph_node(c
, t
, w
, x
), n1(gn1
), n2(gn2
)
ligature_node::~ligature_node()
node
*ligature_node::copy()
return new ligature_node(ci
, tf
, wid
, n1
->copy(), n2
->copy());
return new ligature_node(ci
, tf
, n1
->copy(), n2
->copy());
void ligature_node::ascii_print(ascii_output_file
*ascii
)
hyphen_list
*ligature_node::get_hyphen_list(hyphen_list
*tail
)
return n1
->get_hyphen_list(n2
->get_hyphen_list(tail
));
node
*ligature_node::add_self(node
*n
, hyphen_list
**p
)
kern_pair_node::kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
)
: node(x
), n1(first
), n2(second
), amount(n
)
dbreak_node::dbreak_node(node
*n
, node
*p
, node
*x
)
: node(x
), none(n
), pre(p
), post(0)
node
*dbreak_node::merge_glyph_node(glyph_node
*gn
)
glyph_node
*gn2
= (glyph_node
*)gn
->copy();
node
*new_none
= none
? none
->merge_glyph_node(gn
) : 0;
node
*new_post
= post
? post
->merge_glyph_node(gn2
) : 0;
if (new_none
== 0 && new_post
== 0) {
node
*kern_pair_node::merge_glyph_node(glyph_node
*gn
)
node
*nd
= n2
->merge_glyph_node(gn
);
hunits
kern_pair_node::italic_correction()
return n2
->italic_correction();
hunits
kern_pair_node::subscript_correction()
return n2
->subscript_correction();
node
*kern_pair_node::add_discretionary_hyphen()
charinfo
*hci
= get_charinfo(HYPHEN_SYMBOL
);
tfont
*tf
= n2
->get_tfont();
glyph_node
*gn
= new glyph_node(hci
, tf
);
node
*nn
= n
->merge_glyph_node(gn
);
return new dbreak_node(this, nn
, next1
);
kern_pair_node::~kern_pair_node()
dbreak_node::~dbreak_node()
node
*kern_pair_node::copy()
return new kern_pair_node(amount
, n1
->copy(), n2
->copy());
node
*copy_node_list(node
*n
)
void delete_node_list(node
*n
)
node
*dbreak_node::copy()
dbreak_node
*p
= new dbreak_node(copy_node_list(none
), copy_node_list(pre
));
p
->post
= copy_node_list(post
);
hyphen_list
*node::get_hyphen_list(hyphen_list
*tail
)
hyphen_list
*kern_pair_node::get_hyphen_list(hyphen_list
*tail
)
return n1
->get_hyphen_list(n2
->get_hyphen_list(tail
));
class hyphen_inhibitor_node
: public node
{
hyphen_inhibitor_node(node
*nd
= 0);
hyphenation_type
get_hyphenation_type();
hyphen_inhibitor_node::hyphen_inhibitor_node(node
*nd
) : node(nd
)
node
*hyphen_inhibitor_node::copy()
return new hyphen_inhibitor_node
;
int hyphen_inhibitor_node::same(node
*)
const char *hyphen_inhibitor_node::type()
return "hyphen_inhibitor_node";
hyphenation_type
hyphen_inhibitor_node::get_hyphenation_type()
/* add_discretionary_hyphen methods */
node
*dbreak_node::add_discretionary_hyphen()
post
= post
->add_discretionary_hyphen();
none
= none
->add_discretionary_hyphen();
node
*node::add_discretionary_hyphen()
return new hyphen_inhibitor_node(this);
charinfo
*hci
= get_charinfo(HYPHEN_SYMBOL
);
glyph_node
*gn
= new glyph_node(hci
, tf
);
node
*n1
= n
->merge_glyph_node(gn
);
return new dbreak_node(this, n1
, next1
);
node
*node::merge_self(node
*)
node
*node::add_self(node
*n
, hyphen_list
** /*p*/)
node
*kern_pair_node::add_self(node
*n
, hyphen_list
**p
)
node
*node::last_char_node()
hunits
hmotion_node::width()
return points_to_units(10);
hunits
kern_pair_node::width()
return n1
->width() + n2
->width() + amount
;
node
*kern_pair_node::last_char_node()
node
*nd
= n2
->last_char_node();
return n1
->last_char_node();
hunits
dbreak_node::width()
for (node
*n
= none
; n
!= 0; n
= n
->next
)
node
*dbreak_node::last_char_node()
for (node
*n
= none
; n
; n
= n
->next
) {
node
*last
= n
->last_char_node();
hunits
dbreak_node::italic_correction()
return none
? none
->italic_correction() : H0
;
hunits
dbreak_node::subscript_correction()
return none
? none
->subscript_correction() : H0
;
class italic_corrected_node
: public node
{
italic_corrected_node(node
*, hunits
, node
* = 0);
~italic_corrected_node();
void ascii_print(ascii_output_file
*);
void vertical_extent(vunits
*, vunits
*);
int overlaps_horizontally();
int overlaps_vertically();
hyphenation_type
get_hyphenation_type();
hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
void tprint(troff_output_file
*);
hunits
subscript_correction();
node
*add_self(node
*, hyphen_list
**);
node
*node::add_italic_correction(hunits
*width
)
hunits ic
= italic_correction();
return new italic_corrected_node(this, ic
, next1
);
italic_corrected_node::italic_corrected_node(node
*nn
, hunits xx
, node
*p
)
italic_corrected_node::~italic_corrected_node()
node
*italic_corrected_node::copy()
return new italic_corrected_node(n
->copy(), x
);
hunits
italic_corrected_node::width()
void italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
n
->vertical_extent(min
, max
);
void italic_corrected_node::tprint(troff_output_file
*out
)
hunits
italic_corrected_node::skew()
hunits
italic_corrected_node::subscript_correction()
return n
->subscript_correction() - x
;
void italic_corrected_node::ascii_print(ascii_output_file
*out
)
int italic_corrected_node::ends_sentence()
return n
->ends_sentence();
int italic_corrected_node::overlaps_horizontally()
return n
->overlaps_horizontally();
int italic_corrected_node::overlaps_vertically()
return n
->overlaps_vertically();
node
*italic_corrected_node::last_char_node()
return n
->last_char_node();
tfont
*italic_corrected_node::get_tfont()
hyphenation_type
italic_corrected_node::get_hyphenation_type()
return n
->get_hyphenation_type();
node
*italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
nd
= nd
->add_italic_correction(¬_interested
);
hyphen_list
*italic_corrected_node::get_hyphen_list(hyphen_list
*tail
)
return n
->get_hyphen_list(tail
);
int italic_corrected_node::character_type()
return n
->character_type();
class break_char_node
: public node
{
break_char_node(node
*, int, node
* = 0);
node
*add_self(node
*, hyphen_list
**);
hyphen_list
*get_hyphen_list(hyphen_list
*s
= 0);
void tprint(troff_output_file
*);
void zero_width_tprint(troff_output_file
*);
void ascii_print(ascii_output_file
*);
hyphenation_type
get_hyphenation_type();
int overlaps_vertically();
int overlaps_horizontally();
break_char_node::break_char_node(node
*n
, int c
, node
*x
)
: node(x
), ch(n
), break_code(c
)
break_char_node::~break_char_node()
node
*break_char_node::copy()
return new break_char_node(ch
->copy(), break_code
);
hunits
break_char_node::width()
vunits
break_char_node::vertical_width()
return ch
->vertical_width();
node
*break_char_node::last_char_node()
return ch
->last_char_node();
int break_char_node::character_type()
return ch
->character_type();
int break_char_node::ends_sentence()
return ch
->ends_sentence();
node
*break_char_node::add_self(node
*n
, hyphen_list
**p
)
assert((*p
)->hyphenation_code
== 0);
if ((*p
)->breakable
&& (break_code
& 1)) {
n
= new space_node(H0
, n
);
if ((*p
)->breakable
&& (break_code
& 2)) {
n
= new space_node(H0
, n
);
hyphen_list
*break_char_node::get_hyphen_list(hyphen_list
*tail
)
return new hyphen_list(0, tail
);
hyphenation_type
break_char_node::get_hyphenation_type()
void break_char_node::ascii_print(ascii_output_file
*ascii
)
int break_char_node::overlaps_vertically()
return ch
->overlaps_vertically();
int break_char_node::overlaps_horizontally()
return ch
->overlaps_horizontally();
units
break_char_node::size()
tfont
*break_char_node::get_tfont()
node
*extra_size_node::copy()
return new extra_size_node(n
);
node
*vertical_size_node::copy()
return new vertical_size_node(n
);
node
*hmotion_node::copy()
return new hmotion_node(n
);
node
*space_char_hmotion_node::copy()
return new space_char_hmotion_node(n
);
node
*vmotion_node::copy()
return new vmotion_node(n
);
node
*transparent_dummy_node::copy()
return new transparent_dummy_node
;
hline_node::~hline_node()
return new hline_node(x
, n
? n
->copy() : 0);
hunits
hline_node::width()
vline_node::~vline_node()
return new vline_node(x
, n
? n
->copy() : 0);
hunits
vline_node::width()
return n
== 0 ? H0
: n
->width();
zero_width_node::zero_width_node(node
*nd
) : n(nd
)
zero_width_node::~zero_width_node()
node
*zero_width_node::copy()
return new zero_width_node(copy_node_list(n
));
int node_list_character_type(node
*p
)
t
|= p
->character_type();
int zero_width_node::character_type()
return node_list_character_type(n
);
void node_list_vertical_extent(node
*p
, vunits
*min
, vunits
*max
)
p
->vertical_extent(&v1
, &v2
);
cur_vpos
+= p
->vertical_width();
void zero_width_node::vertical_extent(vunits
*min
, vunits
*max
)
node_list_vertical_extent(n
, min
, max
);
overstrike_node::overstrike_node() : max_width(H0
), list(0)
overstrike_node::~overstrike_node()
node
*overstrike_node::copy()
overstrike_node
*on
= new overstrike_node
;
for (node
*tem
= list
; tem
; tem
= tem
->next
)
on
->overstrike(tem
->copy());
void overstrike_node::overstrike(node
*n
)
for (node
**p
= &list
; *p
; p
= &(*p
)->next
)
hunits
overstrike_node::width()
bracket_node::bracket_node() : max_width(H0
), list(0)
bracket_node::~bracket_node()
node
*bracket_node::copy()
bracket_node
*on
= new bracket_node
;
for (node
*tem
= list
; tem
; tem
= tem
->next
)
on
->bracket(tem
->copy());
void bracket_node::bracket(node
*n
)
hunits
bracket_node::width()
int node::merge_space(hunits
)
space_node
*space_node::free_list
= 0;
void *space_node::operator new(size_t n
)
assert(n
== sizeof(space_node
));
free_list
= (space_node
*)new char[sizeof(space_node
)*BLOCK
];
for (int i
= 0; i
< BLOCK
- 1; i
++)
free_list
[i
].next
= free_list
+ i
+ 1;
free_list
[BLOCK
-1].next
= 0;
space_node
*p
= free_list
;
free_list
= (space_node
*)(free_list
->next
);
inline void space_node::operator delete(void *p
)
((space_node
*)p
)->next
= free_list
;
free_list
= (space_node
*)p
;
space_node::space_node(hunits nn
, node
*p
) : node(p
), n(nn
), set(0)
space_node::space_node(hunits nn
, int s
, node
*p
) : node(p
), n(nn
), set(s
)
space_node::~space_node()
return new space_node(n
, set
);
int space_node::nspaces()
int space_node::merge_space(hunits h
)
hunits
space_node::width()
void node::spread_space(int*, hunits
*)
void space_node::spread_space(int *nspaces
, hunits
*desired_space
)
hunits extra
= *desired_space
/ *nspaces
;
void node::freeze_space()
void space_node::freeze_space()
diverted_space_node::diverted_space_node(vunits d
, node
*p
)
node
*diverted_space_node::copy()
return new diverted_space_node(n
);
diverted_copy_file_node::diverted_copy_file_node(symbol s
, node
*p
)
node
*diverted_copy_file_node::copy()
return new diverted_copy_file_node(filename
);
int node::ends_sentence()
int kern_pair_node::ends_sentence()
switch (n2
->ends_sentence()) {
return n1
->ends_sentence();
int node_list_ends_sentence(node
*n
)
for (; n
!= 0; n
= n
->next
)
switch (n
->ends_sentence()) {
int dbreak_node::ends_sentence()
return node_list_ends_sentence(none
);
int node::overlaps_horizontally()
int node::overlaps_vertically()
int space_node::discardable()
vunits
node::vertical_width()
vunits
vline_node::vertical_width()
vunits
vmotion_node::vertical_width()
int node::character_type()
hunits
node::subscript_correction()
hunits
node::italic_correction()
hunits
node::left_italic_correction()
/* vertical_extent methods */
void node::vertical_extent(vunits
*min
, vunits
*max
)
vunits v
= vertical_width();
void vline_node::vertical_extent(vunits
*min
, vunits
*max
)
node::vertical_extent(min
, max
);
n
->vertical_extent(&cmin
, &cmax
);
// we print the first character and then move up, so
// we print the last character and then move up h
// we move down by h and then print the first character, so
/* ascii_print methods */
static void ascii_print_reverse_node_list(ascii_output_file
*ascii
, node
*n
)
ascii_print_reverse_node_list(ascii
, n
->next
);
void dbreak_node::ascii_print(ascii_output_file
*ascii
)
ascii_print_reverse_node_list(ascii
, none
);
void kern_pair_node::ascii_print(ascii_output_file
*ascii
)
void node::ascii_print(ascii_output_file
*ascii
)
void space_node::ascii_print(ascii_output_file
*ascii
)
void hmotion_node::ascii_print(ascii_output_file
*ascii
)
// this is pretty arbitrary
if (n
>= points_to_units(2))
void space_char_hmotion_node::ascii_print(ascii_output_file
*ascii
)
void node::asciify(macro
*m
)
void glyph_node::asciify(macro
*m
)
unsigned char c
= ci
->get_ascii_code();
void kern_pair_node::asciify(macro
*m
)
static void asciify_reverse_node_list(macro
*m
, node
*n
)
asciify_reverse_node_list(m
, n
->next
);
void dbreak_node::asciify(macro
*m
)
asciify_reverse_node_list(m
, none
);
void ligature_node::asciify(macro
*m
)
void composite_node::asciify(macro
*m
)
unsigned char c
= ci
->get_ascii_code();
void break_char_node::asciify(macro
*m
)
void italic_corrected_node::asciify(macro
*m
)
void left_italic_corrected_node::asciify(macro
*m
)
space_char_hmotion_node::space_char_hmotion_node(hunits i
, node
*next
)
void space_char_hmotion_node::asciify(macro
*m
)
void line_start_node::asciify(macro
*)
void vertical_size_node::asciify(macro
*)
breakpoint
*node::get_breakpoints(hunits
/*width*/, int /*nspaces*/,
breakpoint
*rest
, int /*is_inner*/)
breakpoint
*space_node::get_breakpoints(hunits width
, int ns
, breakpoint
*rest
,
breakpoint
*bp
= new breakpoint
;
bp
->index
= rest
->index
+ 1;
int space_node::nbreaks()
static breakpoint
*node_list_get_breakpoints(node
*p
, hunits
*widthp
,
int ns
, breakpoint
*rest
)
rest
= p
->get_breakpoints(*widthp
,
node_list_get_breakpoints(p
->next
, widthp
, ns
,
breakpoint
*dbreak_node::get_breakpoints(hunits width
, int ns
,
breakpoint
*rest
, int is_inner
)
breakpoint
*bp
= new breakpoint
;
for (node
*tem
= pre
; tem
!= 0; tem
= tem
->next
)
bp
->width
+= tem
->width();
bp
->index
= rest
->index
+ 1;
return node_list_get_breakpoints(none
, &width
, ns
, bp
);
int dbreak_node::nbreaks()
for (node
*tem
= none
; tem
!= 0; tem
= tem
->next
)
void node::split(int /*where*/, node
** /*prep*/, node
** /*postp*/)
void space_node::split(int where
, node
**pre
, node
**post
)
static void node_list_split(node
*p
, int *wherep
, node
**prep
, node
**postp
)
node_list_split(p
->next
, wherep
, prep
, postp
);
p
->split(*wherep
, prep
, postp
);
void dbreak_node::split(int where
, node
**prep
, node
**postp
)
for (node
*tem
= pre
; tem
->next
!= 0; tem
= tem
->next
)
node_list_split(none
, &where
, prep
, postp
);
hyphenation_type
node::get_hyphenation_type()
hyphenation_type
dbreak_node::get_hyphenation_type()
hyphenation_type
kern_pair_node::get_hyphenation_type()
hyphenation_type
dummy_node::get_hyphenation_type()
hyphenation_type
transparent_dummy_node::get_hyphenation_type()
int node::interpret(macro
*)
special_node::special_node(const macro
&m
)
int special_node::same(node
*n
)
return mac
== ((special_node
*)n
)->mac
;
const char *special_node::type()
node
*special_node::copy()
return new special_node(mac
);
void special_node::tprint_start(troff_output_file
*out
)
void special_node::tprint_char(troff_output_file
*out
, unsigned char c
)
void special_node::tprint_end(troff_output_file
*out
)
composite_node::composite_node(node
*p
, charinfo
*c
, font_size s
, node
*x
)
: node(x
), n(p
), ci(c
), sz(s
)
composite_node::~composite_node()
node
*composite_node::copy()
return new composite_node(copy_node_list(n
), ci
, sz
);
hunits
composite_node::width()
for (node
*tem
= n
; tem
; tem
= tem
->next
)
node
*composite_node::last_char_node()
vunits
composite_node::vertical_width()
for (node
*tem
= n
; tem
; tem
= tem
->next
)
v
+= tem
->vertical_width();
units
composite_node::size()
hyphenation_type
composite_node::get_hyphenation_type()
int composite_node::overlaps_horizontally()
return ci
->overlaps_horizontally();
int composite_node::overlaps_vertically()
return ci
->overlaps_vertically();
void composite_node::ascii_print(ascii_output_file
*ascii
)
unsigned char c
= ci
->get_ascii_code();
ascii
->outs(ci
->nm
.contents());
hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
)
return new hyphen_list(ci
->get_hyphenation_code(), tail
);
node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
nn
= nn
->add_discretionary_hyphen();
tfont
*composite_node::get_tfont()
node
*reverse_node_list(node
*n
)
void composite_node::vertical_extent(vunits
*min
, vunits
*max
)
n
= reverse_node_list(n
);
node_list_vertical_extent(n
, min
, max
);
n
= reverse_node_list(n
);
word_space_node::word_space_node(hunits d
, node
*x
) : space_node(d
, x
)
word_space_node::word_space_node(hunits d
, int s
, node
*x
)
node
*word_space_node::copy()
return new word_space_node(n
, set
);
void word_space_node::tprint(troff_output_file
*out
)
draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
)
: code(c
), npoints(np
), sz(s
)
point
= new hvpair
[npoints
];
for (int i
= 0; i
< npoints
; i
++)
int draw_node::same(node
*n
)
draw_node
*nd
= (draw_node
*)n
;
if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
)
for (int i
= 0; i
< npoints
; i
++)
if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
const char *draw_node::type()
hunits
draw_node::width()
for (int i
= 0; i
< npoints
; i
++)
vunits
draw_node::vertical_width()
for (int i
= 0; i
< npoints
; i
++)
return new draw_node(code
, point
, npoints
, sz
);
void draw_node::tprint(troff_output_file
*out
)
out
->draw(code
, point
, npoints
, sz
);
void glyph_node::tprint(troff_output_file
*out
)
tfont
*ptf
= tf
->get_plain();
out
->put_char_width(ci
, ptf
, width(), H0
);
int bold
= tf
->get_bold(&offset
);
hunits w
= ptf
->get_width(ci
);
int cs
= tf
->get_constant_space(&x
);
k
= tf
->get_track_kern();
out
->put_char_width(ci
, ptf
, w
, k
);
void glyph_node::zero_width_tprint(troff_output_file
*out
)
tfont
*ptf
= tf
->get_plain();
int bold
= tf
->get_bold(&offset
);
int cs
= tf
->get_constant_space(&x
);
void break_char_node::tprint(troff_output_file
*t
)
void break_char_node::zero_width_tprint(troff_output_file
*t
)
ch
->zero_width_tprint(t
);
void hline_node::tprint(troff_output_file
*out
)
error("horizontal line drawing character must have positive width");
if (n
->overlaps_horizontally()) {
void vline_node::tprint(troff_output_file
*out
)
int overlaps
= n
->overlaps_vertically();
n
->zero_width_tprint(out
);
n
->zero_width_tprint(out
);
n
->zero_width_tprint(out
);
n
->zero_width_tprint(out
);
void zero_width_node::tprint(troff_output_file
*out
)
n
->zero_width_tprint(out
);
int hpos
= out
->get_hpos();
int vpos
= out
->get_vpos();
void overstrike_node::tprint(troff_output_file
*out
)
for (node
*tem
= list
; tem
; tem
= tem
->next
) {
hunits x
= (max_width
- tem
->width())/2;
tem
->zero_width_tprint(out
);
out
->right(max_width
- pos
);
void bracket_node::tprint(troff_output_file
*out
)
for (node
*tem
= list
; tem
; tem
= tem
->next
)
vunits totalh
= h
*npieces
;
vunits y
= (totalh
+ h
)/2;
for (tem
= list
; tem
; tem
= tem
->next
) {
tem
->zero_width_tprint(out
);
void node::tprint(troff_output_file
*out
)
void node::zero_width_tprint(troff_output_file
*out
)
int hpos
= out
->get_hpos();
int vpos
= out
->get_vpos();
void space_node::tprint(troff_output_file
*out
)
void hmotion_node::tprint(troff_output_file
*out
)
void vmotion_node::tprint(troff_output_file
*out
)
void kern_pair_node::tprint(troff_output_file
*out
)
static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
tprint_reverse_node_list(out
, n
->next
);
void dbreak_node::tprint(troff_output_file
*out
)
tprint_reverse_node_list(out
, none
);
void composite_node::tprint(troff_output_file
*out
)
tprint_reverse_node_list(out
, n
);
node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
int fontno
= env_definite_font(env
);
error("no current font");
assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
int found
= font_table
[fontno
]->contains(s
);
warning(WARN_CHAR
, "can't find numbered character %1",
special_font_list
*sf
= font_table
[fontno
]->sf
;
while (sf
!= 0 && !found
) {
found
= font_table
[fn
]->contains(s
);
sf
= global_special_fonts
;
while (sf
!= 0 && !found
) {
found
= font_table
[fn
]->contains(s
);
&& global_special_fonts
== 0 && font_table
[fontno
]->sf
== 0
for (fn
= 0; fn
< font_table_size
; fn
++)
&& font_table
[fn
]->is_special()
&& font_table
[fn
]->contains(s
)) {
if (!no_error_message
&& s
->first_time_not_found()) {
unsigned char input_code
= s
->get_ascii_code();
warning(WARN_CHAR
, "can't find character `%1'", input_code
);
warning(WARN_CHAR
, "can't find character with input code %1",
warning(WARN_CHAR
, "can't find special character `%1'",
font_size fs
= env
->get_font_size();
int char_height
= env
->get_char_height();
int char_slant
= env
->get_char_slant();
tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
return new glyph_node(s
, tf
);
node
*make_node(charinfo
*ci
, environment
*env
)
switch (ci
->get_special_translation()) {
case charinfo::TRANSLATE_SPACE
:
return new space_char_hmotion_node(env
->get_space_width());
case charinfo::TRANSLATE_DUMMY
:
charinfo
*tem
= ci
->get_translation();
macro
*mac
= ci
->get_macro();
return charinfo_to_node(ci
, env
);
return make_glyph_node(ci
, env
);
int character_exists(charinfo
*ci
, environment
*env
)
if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
charinfo
*tem
= ci
->get_translation();
node
*nd
= make_glyph_node(ci
, env
, 1);
node
*node::add_char(charinfo
*ci
, environment
*env
, hunits
*widthp
)
switch (ci
->get_special_translation()) {
case charinfo::TRANSLATE_SPACE
:
res
= new space_char_hmotion_node(env
->get_space_width(), this);
case charinfo::TRANSLATE_DUMMY
:
return new dummy_node(this);
charinfo
*tem
= ci
->get_translation();
macro
*mac
= ci
->get_macro();
res
= charinfo_to_node(ci
, env
);
node
*gn
= make_glyph_node(ci
, env
);
hunits old_width
= width();
node
*p
= gn
->merge_self(this);
*widthp
+= p
->width() - old_width
;
if (ci
->can_break_before())
if (ci
->can_break_after())
res
= new break_char_node(res
, break_code
, next1
);
int same_node(node
*n1
, node
*n2
)
return n1
->type() == n2
->type() && n1
->same(n2
);
int same_node_list(node
*n1
, node
*n2
)
if (n1
->type() != n2
->type() || !n1
->same(n2
))
int extra_size_node::same(node
*nd
)
return n
== ((extra_size_node
*)nd
)->n
;
const char *extra_size_node::type()
return "extra_size_node";
int vertical_size_node::same(node
*nd
)
return n
== ((vertical_size_node
*)nd
)->n
;
const char *vertical_size_node::type()
return "vertical_size_node";
int hmotion_node::same(node
*nd
)
return n
== ((hmotion_node
*)nd
)->n
;
const char *hmotion_node::type()
int space_char_hmotion_node::same(node
*nd
)
return n
== ((space_char_hmotion_node
*)nd
)->n
;
const char *space_char_hmotion_node::type()
return "space_char_hmotion_node";
int vmotion_node::same(node
*nd
)
return n
== ((vmotion_node
*)nd
)->n
;
const char *vmotion_node::type()
int hline_node::same(node
*nd
)
return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
const char *hline_node::type()
int vline_node::same(node
*nd
)
return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
const char *vline_node::type()
int dummy_node::same(node
* /*nd*/)
const char *dummy_node::type()
int transparent_dummy_node::same(node
* /*nd*/)
const char *transparent_dummy_node::type()
return "transparent_dummy_node";
int transparent_dummy_node::ends_sentence()
int zero_width_node::same(node
*nd
)
return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
const char *zero_width_node::type()
return "zero_width_node";
int italic_corrected_node::same(node
*nd
)
return (x
== ((italic_corrected_node
*)nd
)->x
&& same_node(n
, ((italic_corrected_node
*)nd
)->n
));
const char *italic_corrected_node::type()
return "italic_corrected_node";
left_italic_corrected_node::left_italic_corrected_node(node
*x
)
left_italic_corrected_node::~left_italic_corrected_node()
node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
hunits lic
= gn
->left_italic_correction();
node
*nd
= n
->merge_glyph_node(gn
);
x
= n
->left_italic_correction();
node
*left_italic_corrected_node::copy()
left_italic_corrected_node
*nd
= new left_italic_corrected_node
;
void left_italic_corrected_node::tprint(troff_output_file
*out
)
const char *left_italic_corrected_node::type()
return "left_italic_corrected_node";
int left_italic_corrected_node::same(node
*nd
)
return (x
== ((left_italic_corrected_node
*)nd
)->x
&& same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
hunits
left_italic_corrected_node::width()
return n
? n
->width() + x
: H0
;
void left_italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
n
->vertical_extent(min
, max
);
node::vertical_extent(min
, max
);
hunits
left_italic_corrected_node::skew()
return n
? n
->skew() + x
/2 : H0
;
hunits
left_italic_corrected_node::subscript_correction()
return n
? n
->subscript_correction() : H0
;
hunits
left_italic_corrected_node::italic_correction()
return n
? n
->italic_correction() : H0
;
int left_italic_corrected_node::ends_sentence()
return n
? n
->ends_sentence() : 0;
int left_italic_corrected_node::overlaps_horizontally()
return n
? n
->overlaps_horizontally() : 0;
int left_italic_corrected_node::overlaps_vertically()
return n
? n
->overlaps_vertically() : 0;
node
*left_italic_corrected_node::last_char_node()
return n
? n
->last_char_node() : 0;
tfont
*left_italic_corrected_node::get_tfont()
return n
? n
->get_tfont() : 0;
hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
return n
->get_hyphenation_type();
hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
)
return n
? n
->get_hyphen_list(tail
) : tail
;
node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
nd
= new left_italic_corrected_node(nd
);
int left_italic_corrected_node::character_type()
return n
? n
->character_type() : 0;
int overstrike_node::same(node
*nd
)
return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
const char *overstrike_node::type()
return "overstrike_node";
int bracket_node::same(node
*nd
)
return same_node_list(list
, ((bracket_node
*)nd
)->list
);
const char *bracket_node::type()
int composite_node::same(node
*nd
)
return ci
== ((composite_node
*)nd
)->ci
&& same_node_list(n
, ((composite_node
*)nd
)->n
);
const char *composite_node::type()
int glyph_node::same(node
*nd
)
return ci
== ((glyph_node
*)nd
)->ci
&& tf
== ((glyph_node
*)nd
)->tf
;
const char *glyph_node::type()
int ligature_node::same(node
*nd
)
return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
&& same_node(n2
, ((ligature_node
*)nd
)->n2
)
&& glyph_node::same(nd
));
const char *ligature_node::type()
int kern_pair_node::same(node
*nd
)
return (amount
== ((kern_pair_node
*)nd
)->amount
&& same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
&& same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
const char *kern_pair_node::type()
int dbreak_node::same(node
*nd
)
return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
&& same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
&& same_node_list(post
, ((dbreak_node
*)nd
)->post
));
const char *dbreak_node::type()
int break_char_node::same(node
*nd
)
return (break_code
== ((break_char_node
*)nd
)->break_code
&& same_node(ch
, ((break_char_node
*)nd
)->ch
));
const char *break_char_node::type()
return "break_char_node";
int line_start_node::same(node
* /*nd*/)
const char *line_start_node::type()
return "line_start_node";
int space_node::same(node
*nd
)
return n
== ((space_node
*)nd
)->n
&& set
== ((space_node
*)nd
)->set
;
const char *space_node::type()
int word_space_node::same(node
*nd
)
return (n
== ((word_space_node
*)nd
)->n
&& set
== ((word_space_node
*)nd
)->set
);
const char *word_space_node::type()
return "word_space_node";
int diverted_space_node::same(node
*nd
)
return n
== ((diverted_space_node
*)nd
)->n
;
const char *diverted_space_node::type()
return "diverted_space_node";
int diverted_copy_file_node::same(node
*nd
)
return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
const char *diverted_copy_file_node::type()
return "diverted_copy_file_node";
// Grow the font_table so that its size is > n.
static void grow_font_table(int n
)
assert(n
>= font_table_size
);
font_info
**old_font_table
= font_table
;
int old_font_table_size
= font_table_size
;
font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
if (font_table_size
<= n
)
font_table_size
= n
+ 10;
font_table
= new font_info
*[font_table_size
];
memcpy(font_table
, old_font_table
,
old_font_table_size
*sizeof(font_info
*));
for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
dictionary
font_translation_dictionary(17);
static symbol
get_font_translation(symbol nm
)
void *p
= font_translation_dictionary
.lookup(nm
);
return p
? symbol((char *)p
) : nm
;
dictionary
font_dictionary(50);
static int mount_font_no_translate(int n
, symbol name
, symbol external_name
)
// We store the address of this char in font_dictionary to indicate
// that we've previously tried to mount the font and failed.
void *p
= font_dictionary
.lookup(external_name
);
fm
= font::load_font(external_name
.contents());
font_dictionary
.lookup(external_name
, &a_char
);
font_dictionary
.lookup(name
, fm
);
error("invalid font `%1'", external_name
.contents());
if (n
>= font_table_size
) {
if (n
- font_table_size
> 1000) {
error("font position too much larger than first unused position");
else if (font_table
[n
] != 0)
font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
int mount_font(int n
, symbol name
, symbol external_name
)
name
= get_font_translation(name
);
if (external_name
.is_null())
external_name
= get_font_translation(external_name
);
return mount_font_no_translate(n
, name
, external_name
);
void mount_style(int n
, symbol name
)
if (n
>= font_table_size
) {
if (n
- font_table_size
> 1000) {
error("font position too much larger than first unused position");
else if (font_table
[n
] != 0)
font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
symbol from
= get_name(1);
if (to
.is_null() || from
== to
)
font_translation_dictionary
.remove(from
);
font_translation_dictionary
.lookup(from
, (void *)to
.contents());
error("negative font position");
symbol internal_name
= get_name(1);
if (!internal_name
.is_null()) {
symbol external_name
= get_long_name(0);
mount_font(n
, internal_name
, external_name
); // ignore error
font_family::font_family(symbol s
)
for (int i
= 0; i
< map_size
; i
++)
font_family::~font_family()
int font_family::make_definite(int i
)
if (i
< map_size
&& map
[i
] >= 0)
if (i
< font_table_size
&& font_table
[i
] != 0) {
int old_map_size
= map_size
;
memcpy(map
, old_map
, old_map_size
*sizeof(int));
for (int j
= old_map_size
; j
< map_size
; j
++)
if (font_table
[i
]->is_style()) {
symbol sty
= font_table
[i
]->get_name();
symbol f
= concat(nm
, sty
);
// don't use symbol_fontno, because that might return a style
// and because we don't want to translate the name
for (n
= 0; n
< font_table_size
; n
++)
if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
&& !font_table
[n
]->is_style())
if (n
>= font_table_size
) {
n
= next_available_font_position();
if (!mount_font_no_translate(n
, f
, f
))
dictionary
family_dictionary(5);
font_family
*lookup_family(symbol nm
)
font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
(void)family_dictionary
.lookup(nm
, f
);
static void invalidate_fontno(int n
)
assert(n
>= 0 && n
< font_table_size
);
dictionary_iterator
iter(family_dictionary
);
while (iter
.get(&nm
, (void **)&fam
)) {
int map_size
= fam
->map_size
;
for (int i
= 0; i
< map_size
; i
++)
error("negative font position");
symbol internal_name
= get_name(1);
if (!internal_name
.is_null())
mount_style(n
, internal_name
);
n
= next_available_font_position();
return curenv
->get_family()->make_definite(n
);
else if (get_integer(&n
)) {
if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
error("bad font number");
return curenv
->get_family()->make_definite(n
);
static int underline_fontno
= 2;
int get_underline_fontno()
static void read_special_fonts(special_font_list
**sp
)
special_font_list
*s
= *sp
;
special_font_list
*tem
= s
;
special_font_list
**p
= sp
;
special_font_list
*tem
= new special_font_list
;
void font_special_request()
read_special_fonts(&font_table
[n
]->sf
);
read_special_fonts(&global_special_fonts
);
int next_available_font_position()
for (int i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
int symbol_fontno(symbol s
)
s
= get_font_translation(s
);
for (int i
= 0; i
< font_table_size
; i
++)
if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
int is_good_fontno(int n
)
return n
>= 0 && n
< font_table_size
&& font_table
[n
] != NULL
;
int get_bold_fontno(int n
)
if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
if (font_table
[n
]->get_bold(&offset
))
return offset
.to_units() + 1;
hunits
env_digit_width(environment
*env
)
node
*n
= make_glyph_node(charset_table
['0'], env
);
hunits
env_space_width(environment
*env
)
int fn
= env_definite_font(env
);
font_size fs
= env
->get_font_size();
if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
return font_table
[fn
]->get_space_width(fs
);
hunits
env_half_narrow_space_width(environment
*env
)
int fn
= env_definite_font(env
);
font_size fs
= env
->get_font_size();
if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
return font_table
[fn
]->get_half_narrow_space_width(fs
);
hunits
env_narrow_space_width(environment
*env
)
int fn
= env_definite_font(env
);
font_size fs
= env
->get_font_size();
if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
return font_table
[fn
]->get_narrow_space_width(fs
);
if (get_number(&offset
, 'u')) {
font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
font_table
[f
]->conditional_unbold(n
);
font_table
[f
]->conditional_unbold(n
);
if (get_number(&offset
, 'u')) {
font_table
[n
]->set_bold(hunits(offset
- 1));
track_kerning_function::track_kerning_function() : non_zero(0)
track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
min_size(min_s
), min_amount(min_a
),
max_size(max_s
), max_amount(max_a
)
int track_kerning_function::operator==(const track_kerning_function
&tk
)
&& min_size
== tk
.min_size
&& min_amount
== tk
.min_amount
&& max_size
== tk
.max_size
&& max_amount
== tk
.max_amount
);
int track_kerning_function::operator!=(const track_kerning_function
&tk
)
|| min_size
!= tk
.min_size
|| min_amount
!= tk
.min_amount
|| max_size
!= tk
.max_size
|| max_amount
!= tk
.max_amount
);
hunits
track_kerning_function::compute(int size
)
if (max_size
<= min_size
)
else if (size
<= min_size
)
else if (size
>= max_size
)
return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
+ scale(min_amount
, max_size
- size
, max_size
- min_size
));
if (!get_number(&min_s
, 'z')
|| !get_hunits(&min_a
, 'p')
|| !get_number(&max_s
, 'z')
|| !get_hunits(&max_a
, 'p'))
error("bad arguments for track kerning");
track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
font_table
[n
]->set_track_kern(tk
);
track_kerning_function tk
;
font_table
[n
]->set_track_kern(tk
);
font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
else if (get_integer(&x
)) {
font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
else if (get_number(&y
, 'z'))
font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
global_ligature_mode
= lig
;
global_ligature_mode
= 1;
global_kern_mode
= k
!= 0;
if (suppress_output_flag
)
the_output
= new suppress_output_file
;
else if (ascii_output_flag
)
the_output
= new ascii_output_file
;
the_output
= new troff_output_file
;
class next_available_font_position_reg
: public reg
{
const char *get_string();
const char *next_available_font_position_reg::get_string()
return itoa(next_available_font_position());
class printing_reg
: public reg
{
const char *get_string();
const char *printing_reg::get_string()
return the_output
->is_printing() ? "1" : "0";
void init_node_requests()
init_request("fp", font_position
);
init_request("sty", style
);
init_request("cs", constant_space
);
init_request("bd", bold_font
);
init_request("uf", underline_font
);
init_request("lg", ligature
);
init_request("kern", kern_request
);
init_request("tkf", track_kern
);
init_request("special", special_request
);
init_request("fspecial", font_special_request
);
init_request("ftr", font_translate
);
number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
number_reg_dictionary
.define(".kern",
new constant_int_reg(&global_kern_mode
));
number_reg_dictionary
.define(".lg",
new constant_int_reg(&global_ligature_mode
));
number_reg_dictionary
.define(".P", new printing_reg
);