2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
25 font_pointer_list::font_pointer_list(font
*f
, font_pointer_list
*fp
)
31 : font_table(0), nfonts(0), font_list(0)
39 font_pointer_list
*tem
= font_list
;
40 font_list
= font_list
->next
;
44 if (ferror(stdout
) || fflush(stdout
) < 0)
45 fatal("output error");
48 void printer::load_font(int n
, const char *nm
)
56 font_table
= new font
*[nfonts
];
57 for (int i
= 0; i
< nfonts
; i
++)
61 font
**old_font_table
= font_table
;
62 int old_nfonts
= nfonts
;
66 font_table
= new font
*[nfonts
];
67 for (int i
= 0; i
< old_nfonts
; i
++)
68 font_table
[i
] = old_font_table
[i
];
69 for (i
= old_nfonts
; i
< nfonts
; i
++)
71 a_delete old_font_table
;
74 font
*f
= find_font(nm
);
78 font
*printer::find_font(const char *nm
)
80 for (font_pointer_list
*p
= font_list
; p
; p
= p
->next
)
81 if (strcmp(p
->p
->get_name(), nm
) == 0)
83 font
*f
= make_font(nm
);
85 fatal("sorry, I can't continue");
86 font_list
= new font_pointer_list(f
, font_list
);
90 font
*printer::make_font(const char *nm
)
92 return font::load_font(nm
);
95 void printer::end_of_line()
99 void printer::special(char *, const environment
*)
103 void printer::draw(int, int *, int, const environment
*)
107 void printer::set_ascii_char(unsigned char c
, const environment
*env
,
113 set_special_char(buf
, env
, widthp
);
116 void printer::set_special_char(const char *nm
, const environment
*env
,
119 int i
= font::name_to_index(nm
);
120 int fn
= env
->fontno
;
121 if (fn
< 0 || fn
>= nfonts
) {
122 error("bad font position `%1'", fn
);
125 font
*f
= font_table
[fn
];
127 error("no font mounted at `%1'", fn
);
130 if (!f
->contains(i
)) {
131 if (nm
[0] != '\0' && nm
[1] == '\0')
132 error("font `%1' does not contain ascii character `%2'",
136 error("font `%1' does not contain special character `%2'",
141 int w
= f
->get_width(i
, env
->size
);
144 set_char(i
, f
, env
, w
);
147 void printer::set_numbered_char(int num
, const environment
*env
, int *widthp
)
149 int i
= font::number_to_index(num
);
150 int fn
= env
->fontno
;
151 if (fn
< 0 || fn
>= nfonts
) {
152 error("bad font position `%1'", fn
);
155 font
*f
= font_table
[fn
];
157 error("no font mounted at `%1'", fn
);
160 if (!f
->contains(i
)) {
161 error("font `%1' does not contain numbered character %2",
166 int w
= f
->get_width(i
, env
->size
);
169 set_char(i
, f
, env
, w
);
172 // This utility function adjusts the specified center of the
173 // arc so that it is equidistant between the specified start
174 // and end points. (p[0], p[1]) is a vector from the current
175 // point to the center; (p[2], p[3]) is a vector from the
176 // center to the end point. If the center can be adjusted,
177 // a vector from the current point to the adjusted center is
178 // stored in c[0], c[1] and 1 is returned. Otherwise 0 is
182 int printer::adjust_arc_center(const int *p
, double *c
)
184 // We move the center along a line parallel to the line between
185 // the specified start point and end point so that the center
186 // is equidistant between the start and end point.
187 // It can be proved (using Lagrange multipliers) that this will
188 // give the point nearest to the specified center that is equidistant
189 // between the start and end point.
191 double x
= p
[0] + p
[2]; // (x, y) is the end point
192 double y
= p
[1] + p
[3];
193 double n
= x
*x
+ y
*y
;
197 double k
= .5 - (c
[0]*x
+ c
[1]*y
)/n
;
206 int printer::adjust_arc_center(const int *p
, double *c
)
208 int x
= p
[0] + p
[2]; // (x, y) is the end point
210 // Start at the current point; go in the direction of the specified
211 // center point until we reach a point that is equidistant between
212 // the specified starting point and the specified end point. Place
213 // the center of the arc there.
214 double n
= p
[0]*double(x
) + p
[1]*double(y
);
216 double k
= (double(x
)*x
+ double(y
)*y
)/(2.0*n
);
217 // (cx, cy) is our chosen center
223 // We would never reach such a point. So instead start at the
224 // specified end point of the arc. Go towards the specified
225 // center point until we reach a point that is equidistant between
226 // the specified start point and specified end point. Place
227 // the center of the arc there.
228 n
= p
[2]*double(x
) + p
[3]*double(y
);
230 double k
= 1 - (double(x
)*x
+ double(y
)*y
)/(2.0*n
);
231 // (c[0], c[1]) is our chosen center
232 c
[0] = p
[0] + k
*p
[2];
233 c
[1] = p
[1] + k
*p
[3];