* src/libs/libgroff/htmlindicate.cc: Added library file which is now
[s-roff.git] / src / preproc / pic / troff.cc
blob53761b2f2cffaf36402d1fb8e3415c723ed8f8d0
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 #include "pic.h"
22 #include "common.h"
23 #include "htmlindicate.h"
26 const double RELATIVE_THICKNESS = -1.0;
27 const double BAD_THICKNESS = -2.0;
29 class simple_output : public common_output {
30 virtual void simple_line(const position &, const position &) = 0;
31 virtual void simple_spline(const position &, const position *, int n) = 0;
32 virtual void simple_arc(const position &, const position &,
33 const position &) = 0;
34 virtual void simple_circle(int, const position &, double rad) = 0;
35 virtual void simple_ellipse(int, const position &, const distance &) = 0;
36 virtual void simple_polygon(int, const position *, int) = 0;
37 virtual void line_thickness(double) = 0;
38 virtual void set_fill(double) = 0;
39 void dot(const position &, const line_type &) = 0;
40 public:
41 void start_picture(double sc, const position &ll, const position &ur) = 0;
42 void finish_picture() = 0;
43 void text(const position &, text_piece *, int, double) = 0;
44 void line(const position &, const position *, int n,
45 const line_type &);
46 void polygon(const position *, int n,
47 const line_type &, double);
48 void spline(const position &, const position *, int n,
49 const line_type &);
50 void arc(const position &, const position &, const position &,
51 const line_type &);
52 void circle(const position &, double rad, const line_type &, double);
53 void ellipse(const position &, const distance &, const line_type &, double);
54 int supports_filled_polygons();
57 int simple_output::supports_filled_polygons()
59 return driver_extension_flag != 0;
62 void simple_output::arc(const position &start, const position &cent,
63 const position &end, const line_type &lt)
65 switch (lt.type) {
66 case line_type::solid:
67 line_thickness(lt.thickness);
68 simple_arc(start, cent, end);
69 break;
70 case line_type::invisible:
71 break;
72 case line_type::dashed:
73 dashed_arc(start, cent, end, lt);
74 break;
75 case line_type::dotted:
76 dotted_arc(start, cent, end, lt);
77 break;
81 void simple_output::line(const position &start, const position *v, int n,
82 const line_type &lt)
84 position pos = start;
85 line_thickness(lt.thickness);
86 for (int i = 0; i < n; i++) {
87 switch (lt.type) {
88 case line_type::solid:
89 simple_line(pos, v[i]);
90 break;
91 case line_type::dotted:
93 distance vec(v[i] - pos);
94 double dist = hypot(vec);
95 int ndots = int(dist/lt.dash_width + .5);
96 if (ndots == 0)
97 dot(pos, lt);
98 else {
99 vec /= double(ndots);
100 for (int j = 0; j <= ndots; j++)
101 dot(pos + vec*j, lt);
104 break;
105 case line_type::dashed:
107 distance vec(v[i] - pos);
108 double dist = hypot(vec);
109 if (dist <= lt.dash_width*2.0)
110 simple_line(pos, v[i]);
111 else {
112 int ndashes = int((dist - lt.dash_width)/(lt.dash_width*2.0) + .5);
113 distance dash_vec = vec*(lt.dash_width/dist);
114 double dash_gap = (dist - lt.dash_width)/ndashes;
115 distance dash_gap_vec = vec*(dash_gap/dist);
116 for (int j = 0; j <= ndashes; j++) {
117 position s(pos + dash_gap_vec*j);
118 simple_line(s, s + dash_vec);
122 break;
123 case line_type::invisible:
124 break;
125 default:
126 assert(0);
128 pos = v[i];
132 void simple_output::spline(const position &start, const position *v, int n,
133 const line_type &lt)
135 line_thickness(lt.thickness);
136 simple_spline(start, v, n);
139 void simple_output::polygon(const position *v, int n,
140 const line_type &lt, double fill)
142 if (driver_extension_flag) {
143 if (fill >= 0.0) {
144 set_fill(fill);
145 simple_polygon(1, v, n);
148 if (lt.type == line_type::solid && driver_extension_flag) {
149 line_thickness(lt.thickness);
150 simple_polygon(0, v, n);
152 else if (lt.type != line_type::invisible) {
153 line_thickness(lt.thickness);
154 line(v[n - 1], v, n, lt);
158 void simple_output::circle(const position &cent, double rad,
159 const line_type &lt, double fill)
161 if (driver_extension_flag && fill >= 0.0) {
162 set_fill(fill);
163 simple_circle(1, cent, rad);
165 line_thickness(lt.thickness);
166 switch (lt.type) {
167 case line_type::invisible:
168 break;
169 case line_type::dashed:
170 dashed_circle(cent, rad, lt);
171 break;
172 case line_type::dotted:
173 dotted_circle(cent, rad, lt);
174 break;
175 case line_type::solid:
176 simple_circle(0, cent, rad);
177 break;
178 default:
179 assert(0);
183 void simple_output::ellipse(const position &cent, const distance &dim,
184 const line_type &lt, double fill)
186 if (driver_extension_flag && fill >= 0.0) {
187 set_fill(fill);
188 simple_ellipse(1, cent, dim);
190 if (lt.type != line_type::invisible)
191 line_thickness(lt.thickness);
192 switch (lt.type) {
193 case line_type::invisible:
194 break;
195 case line_type::dotted:
196 case line_type::dashed:
197 case line_type::solid:
198 simple_ellipse(0, cent, dim);
199 break;
200 default:
201 assert(0);
205 #define FILL_MAX 1000
207 class troff_output : public simple_output {
208 const char *last_filename;
209 position upper_left;
210 double height;
211 double scale;
212 double last_line_thickness;
213 double last_fill;
214 public:
215 troff_output();
216 ~troff_output();
217 void start_picture(double, const position &ll, const position &ur);
218 void finish_picture();
219 void text(const position &, text_piece *, int, double);
220 void dot(const position &, const line_type &);
221 void command(const char *, const char *, int);
222 void set_location(const char *, int);
223 void simple_line(const position &, const position &);
224 void simple_spline(const position &, const position *, int n);
225 void simple_arc(const position &, const position &, const position &);
226 void simple_circle(int, const position &, double rad);
227 void simple_ellipse(int, const position &, const distance &);
228 void simple_polygon(int, const position *, int);
229 void line_thickness(double p);
230 void set_fill(double);
231 position transform(const position &);
234 output *make_troff_output()
236 return new troff_output;
239 troff_output::troff_output()
240 : last_filename(0), last_line_thickness(BAD_THICKNESS), last_fill(-1.0)
244 troff_output::~troff_output()
248 inline position troff_output::transform(const position &pos)
250 return position((pos.x - upper_left.x)/scale,
251 (upper_left.y - pos.y)/scale);
254 #define FILL_REG "00"
256 // If this register > 0, then pic will generate \X'ps: ...' commands
257 // if the aligned attribute is used.
258 #define GROPS_REG "0p"
260 // If this register is defined, geqn won't produce `\x's.
261 #define EQN_NO_EXTRA_SPACE_REG "0x"
263 void troff_output::start_picture(double sc,
264 const position &ll, const position &ur)
266 upper_left.x = ll.x;
267 upper_left.y = ur.y;
268 scale = compute_scale(sc, ll, ur);
269 height = (ur.y - ll.y)/scale;
270 double width = (ur.x - ll.x)/scale;
271 printf(".PS %.3fi %.3fi", height, width);
272 if (args)
273 printf(" %s\n", args);
274 else
275 putchar('\n');
276 graphic_start();
277 printf(".\\\" %g %g %g %g\n", ll.x, ll.y, ur.x, ur.y);
278 printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height, width, 0.0);
279 printf(".nr " FILL_REG " \\n(.u\n.nf\n");
280 printf(".nr " EQN_NO_EXTRA_SPACE_REG " 1\n");
281 // This guarantees that if the picture is used in a diversion it will
282 // have the right width.
283 printf("\\h'%.3fi'\n.sp -1\n", width);
286 void troff_output::finish_picture()
288 line_thickness(BAD_THICKNESS);
289 last_fill = -1.0; // force it to be reset for each picture
290 if (!flyback_flag)
291 printf(".sp %.3fi+1\n", height);
292 printf(".if \\n(" FILL_REG " .fi\n");
293 printf(".br\n");
294 printf(".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
295 graphic_end();
296 // this is a little gross
297 set_location(current_filename, current_lineno);
298 fputs(flyback_flag ? ".PF\n" : ".PE\n", stdout);
301 void troff_output::command(const char *s,
302 const char *filename, int lineno)
304 if (filename != 0)
305 set_location(filename, lineno);
306 fputs(s, stdout);
307 putchar('\n');
310 void troff_output::simple_circle(int filled, const position &cent, double rad)
312 position c = transform(cent);
313 printf("\\h'%.3fi'"
314 "\\v'%.3fi'"
315 "\\D'%c%.3fi'"
316 "\n.sp -1\n",
317 c.x - rad/scale,
318 c.y,
319 (filled ? 'C' : 'c'),
320 rad*2.0/scale);
323 void troff_output::simple_ellipse(int filled, const position &cent,
324 const distance &dim)
326 position c = transform(cent);
327 printf("\\h'%.3fi'"
328 "\\v'%.3fi'"
329 "\\D'%c%.3fi %.3fi'"
330 "\n.sp -1\n",
331 c.x - dim.x/(2.0*scale),
332 c.y,
333 (filled ? 'E' : 'e'),
334 dim.x/scale, dim.y/scale);
337 void troff_output::simple_arc(const position &start, const distance &cent,
338 const distance &end)
340 position s = transform(start);
341 position c = transform(cent);
342 distance cv = c - s;
343 distance ev = transform(end) - c;
344 printf("\\h'%.3fi'"
345 "\\v'%.3fi'"
346 "\\D'a%.3fi %.3fi %.3fi %.3fi'"
347 "\n.sp -1\n",
348 s.x, s.y, cv.x, cv.y, ev.x, ev.y);
351 void troff_output::simple_line(const position &start, const position &end)
353 position s = transform(start);
354 distance ev = transform(end) - s;
355 printf("\\h'%.3fi'"
356 "\\v'%.3fi'"
357 "\\D'l%.3fi %.3fi'"
358 "\n.sp -1\n",
359 s.x, s.y, ev.x, ev.y);
362 void troff_output::simple_spline(const position &start,
363 const position *v, int n)
365 position pos = transform(start);
366 printf("\\h'%.3fi'"
367 "\\v'%.3fi'",
368 pos.x, pos.y);
369 fputs("\\D'~", stdout);
370 for (int i = 0; i < n; i++) {
371 position temp = transform(v[i]);
372 distance d = temp - pos;
373 pos = temp;
374 if (i != 0)
375 putchar(' ');
376 printf("%.3fi %.3fi", d.x, d.y);
378 printf("'\n.sp -1\n");
381 // a solid polygon
383 void troff_output::simple_polygon(int filled, const position *v, int n)
385 position pos = transform(v[0]);
386 printf("\\h'%.3fi'"
387 "\\v'%.3fi'",
388 pos.x, pos.y);
389 printf("\\D'%c", (filled ? 'P' : 'p'));
390 for (int i = 1; i < n; i++) {
391 position temp = transform(v[i]);
392 distance d = temp - pos;
393 pos = temp;
394 if (i != 1)
395 putchar(' ');
396 printf("%.3fi %.3fi", d.x, d.y);
398 printf("'\n.sp -1\n");
401 const double TEXT_AXIS = 0.22; // in ems
403 static const char *choose_delimiter(const char *text)
405 if (strchr(text, '\'') == 0)
406 return "'";
407 else
408 return "\\(ts";
411 void troff_output::text(const position &center, text_piece *v, int n,
412 double ang)
414 line_thickness(BAD_THICKNESS); // the text might use lines (eg in equations)
415 int rotate_flag = 0;
416 if (driver_extension_flag && ang != 0.0) {
417 rotate_flag = 1;
418 position c = transform(center);
419 printf(".if \\n(" GROPS_REG " \\{\\\n"
420 "\\h'%.3fi'"
421 "\\v'%.3fi'"
422 "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
423 "\n.sp -1\n"
424 ".\\}\n",
425 c.x, c.y, -ang*180.0/M_PI);
427 for (int i = 0; i < n; i++)
428 if (v[i].text != 0 && *v[i].text != '\0') {
429 position c = transform(center);
430 if (v[i].filename != 0)
431 set_location(v[i].filename, v[i].lineno);
432 printf("\\h'%.3fi", c.x);
433 const char *delim = choose_delimiter(v[i].text);
434 if (v[i].adj.h == RIGHT_ADJUST)
435 printf("-\\w%s%s%su", delim, v[i].text, delim);
436 else if (v[i].adj.h != LEFT_ADJUST)
437 printf("-(\\w%s%s%su/2u)", delim, v[i].text, delim);
438 putchar('\'');
439 printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
440 c.y,
441 n - 1,
443 TEXT_AXIS);
444 if (v[i].adj.v == ABOVE_ADJUST)
445 printf("-.5v");
446 else if (v[i].adj.v == BELOW_ADJUST)
447 printf("+.5v");
448 putchar('\'');
449 fputs(v[i].text, stdout);
450 fputs("\n.sp -1\n", stdout);
452 if (rotate_flag)
453 printf(".if '\\*(.T'ps' \\{\\\n"
454 "\\X'ps: exec grestore'\n.sp -1\n"
455 ".\\}\n");
458 void troff_output::line_thickness(double p)
460 if (p < 0.0)
461 p = RELATIVE_THICKNESS;
462 if (driver_extension_flag && p != last_line_thickness) {
463 printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p, -p);
464 last_line_thickness = p;
468 void troff_output::set_fill(double f)
470 if (driver_extension_flag && f != last_fill) {
471 printf("\\D'f %du'\\h'%du'\n.sp -1\n", int(f*FILL_MAX), -int(f*FILL_MAX));
472 last_fill = f;
476 const double DOT_AXIS = .044;
478 void troff_output::dot(const position &cent, const line_type &lt)
480 if (driver_extension_flag) {
481 line_thickness(lt.thickness);
482 simple_line(cent, cent);
484 else {
485 position c = transform(cent);
486 printf("\\h'%.3fi-(\\w'.'u/2u)'"
487 "\\v'%.3fi+%.2fm'"
488 ".\n.sp -1\n",
489 c.x,
490 c.y,
491 DOT_AXIS);
495 void troff_output::set_location(const char *s, int n)
497 if (last_filename != 0 && strcmp(s, last_filename) == 0)
498 printf(".lf %d\n", n);
499 else {
500 printf(".lf %d %s\n", n, s);
501 last_filename = s;