groff before CVS: release 1.07
[s-roff.git] / libdriver / printer.cc
blobf7e0b5fc43eac2d863a61fa5309e501e43079cd7
1 // -*- C++ -*-
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
10 version.
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
15 for more details.
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. */
21 #include "driver.h"
23 printer *pr = 0;
25 font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp)
26 : p(f), next(fp)
30 printer::printer()
31 : font_table(0), nfonts(0), font_list(0)
35 printer::~printer()
37 a_delete font_table;
38 while (font_list) {
39 font_pointer_list *tem = font_list;
40 font_list = font_list->next;
41 delete tem->p;
42 delete tem;
44 if (ferror(stdout) || fflush(stdout) < 0)
45 fatal("output error");
48 void printer::load_font(int n, const char *nm)
50 assert(n >= 0);
51 if (n >= nfonts) {
52 if (nfonts == 0) {
53 nfonts = 10;
54 if (nfonts <= n)
55 nfonts = n + 1;
56 font_table = new font *[nfonts];
57 for (int i = 0; i < nfonts; i++)
58 font_table[i] = 0;
60 else {
61 font **old_font_table = font_table;
62 int old_nfonts = nfonts;
63 nfonts *= 2;
64 if (n >= nfonts)
65 nfonts = n + 1;
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++)
70 font_table[i] = 0;
71 a_delete old_font_table;
74 font *f = find_font(nm);
75 font_table[n] = f;
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)
82 return p->p;
83 font *f = make_font(nm);
84 if (!f)
85 fatal("sorry, I can't continue");
86 font_list = new font_pointer_list(f, font_list);
87 return f;
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,
108 int *widthp)
110 char buf[2];
111 buf[0] = c;
112 buf[1] = '\0';
113 set_special_char(buf, env, widthp);
116 void printer::set_special_char(const char *nm, const environment *env,
117 int *widthp)
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);
123 return;
125 font *f = font_table[fn];
126 if (f == 0) {
127 error("no font mounted at `%1'", fn);
128 return;
130 if (!f->contains(i)) {
131 if (nm[0] != '\0' && nm[1] == '\0')
132 error("font `%1' does not contain ascii character `%2'",
133 f->get_name(),
134 nm[0]);
135 else
136 error("font `%1' does not contain special character `%2'",
137 f->get_name(),
138 nm);
139 return;
141 int w = f->get_width(i, env->size);
142 if (widthp)
143 *widthp = w;
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);
153 return;
155 font *f = font_table[fn];
156 if (f == 0) {
157 error("no font mounted at `%1'", fn);
158 return;
160 if (!f->contains(i)) {
161 error("font `%1' does not contain numbered character %2",
162 f->get_name(),
163 num);
164 return;
166 int w = f->get_width(i, env->size);
167 if (widthp)
168 *widthp = w;
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
179 // returned.
181 #if 1
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;
194 if (n != 0) {
195 c[0]= double(p[0]);
196 c[1] = double(p[1]);
197 double k = .5 - (c[0]*x + c[1]*y)/n;
198 c[0] += k*x;
199 c[1] += k*y;
200 return 1;
202 else
203 return 0;
205 #else
206 int printer::adjust_arc_center(const int *p, double *c)
208 int x = p[0] + p[2]; // (x, y) is the end point
209 int y = p[1] + p[3];
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);
215 if (n > 0) {
216 double k = (double(x)*x + double(y)*y)/(2.0*n);
217 // (cx, cy) is our chosen center
218 c[0] = k*p[0];
219 c[1] = k*p[1];
220 return 1;
222 else {
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);
229 if (n > 0) {
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];
234 return 1;
236 else
237 return 0;
240 #endif