2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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 virtual void set_color(char *, char *) = 0;
40 virtual void reset_color() = 0;
41 virtual char *get_last_filled() = 0;
42 void dot(const position
&, const line_type
&) = 0;
44 void start_picture(double sc
, const position
&ll
, const position
&ur
) = 0;
45 void finish_picture() = 0;
46 void text(const position
&, text_piece
*, int, double) = 0;
47 void line(const position
&, const position
*, int n
,
49 void polygon(const position
*, int n
,
50 const line_type
&, double);
51 void spline(const position
&, const position
*, int n
,
53 void arc(const position
&, const position
&, const position
&,
55 void circle(const position
&, double rad
, const line_type
&, double);
56 void ellipse(const position
&, const distance
&, const line_type
&, double);
57 int supports_filled_polygons();
60 int simple_output::supports_filled_polygons()
62 return driver_extension_flag
!= 0;
65 void simple_output::arc(const position
&start
, const position
¢
,
66 const position
&end
, const line_type
<
)
69 case line_type::solid
:
70 line_thickness(lt
.thickness
);
71 simple_arc(start
, cent
, end
);
73 case line_type::invisible
:
75 case line_type::dashed
:
76 dashed_arc(start
, cent
, end
, lt
);
78 case line_type::dotted
:
79 dotted_arc(start
, cent
, end
, lt
);
84 void simple_output::line(const position
&start
, const position
*v
, int n
,
88 line_thickness(lt
.thickness
);
89 for (int i
= 0; i
< n
; i
++) {
91 case line_type::solid
:
92 simple_line(pos
, v
[i
]);
94 case line_type::dotted
:
96 distance
vec(v
[i
] - pos
);
97 double dist
= hypot(vec
);
98 int ndots
= int(dist
/lt
.dash_width
+ .5);
102 vec
/= double(ndots
);
103 for (int j
= 0; j
<= ndots
; j
++)
104 dot(pos
+ vec
*j
, lt
);
108 case line_type::dashed
:
110 distance
vec(v
[i
] - pos
);
111 double dist
= hypot(vec
);
112 if (dist
<= lt
.dash_width
*2.0)
113 simple_line(pos
, v
[i
]);
115 int ndashes
= int((dist
- lt
.dash_width
)/(lt
.dash_width
*2.0) + .5);
116 distance dash_vec
= vec
*(lt
.dash_width
/dist
);
117 double dash_gap
= (dist
- lt
.dash_width
)/ndashes
;
118 distance dash_gap_vec
= vec
*(dash_gap
/dist
);
119 for (int j
= 0; j
<= ndashes
; j
++) {
120 position
s(pos
+ dash_gap_vec
*j
);
121 simple_line(s
, s
+ dash_vec
);
126 case line_type::invisible
:
135 void simple_output::spline(const position
&start
, const position
*v
, int n
,
138 line_thickness(lt
.thickness
);
139 simple_spline(start
, v
, n
);
142 void simple_output::polygon(const position
*v
, int n
,
143 const line_type
<
, double fill
)
145 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
146 if (get_last_filled() == 0)
148 simple_polygon(1, v
, n
);
150 if (lt
.type
== line_type::solid
&& driver_extension_flag
) {
151 line_thickness(lt
.thickness
);
152 simple_polygon(0, v
, n
);
154 else if (lt
.type
!= line_type::invisible
) {
155 line_thickness(lt
.thickness
);
156 line(v
[n
- 1], v
, n
, lt
);
160 void simple_output::circle(const position
¢
, double rad
,
161 const line_type
<
, double fill
)
163 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
164 if (get_last_filled() == 0)
166 simple_circle(1, cent
, rad
);
168 line_thickness(lt
.thickness
);
170 case line_type::invisible
:
172 case line_type::dashed
:
173 dashed_circle(cent
, rad
, lt
);
175 case line_type::dotted
:
176 dotted_circle(cent
, rad
, lt
);
178 case line_type::solid
:
179 simple_circle(0, cent
, rad
);
186 void simple_output::ellipse(const position
¢
, const distance
&dim
,
187 const line_type
<
, double fill
)
189 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
190 if (get_last_filled() == 0)
192 simple_ellipse(1, cent
, dim
);
194 if (lt
.type
!= line_type::invisible
)
195 line_thickness(lt
.thickness
);
197 case line_type::invisible
:
199 case line_type::dotted
:
200 case line_type::dashed
:
201 case line_type::solid
:
202 simple_ellipse(0, cent
, dim
);
209 #define FILL_MAX 1000
211 class troff_output
: public simple_output
{
212 const char *last_filename
;
216 double last_line_thickness
;
218 char *last_filled
; // color
219 char *last_outlined
; // color
223 void start_picture(double, const position
&ll
, const position
&ur
);
224 void finish_picture();
225 void text(const position
&, text_piece
*, int, double);
226 void dot(const position
&, const line_type
&);
227 void command(const char *, const char *, int);
228 void set_location(const char *, int);
229 void simple_line(const position
&, const position
&);
230 void simple_spline(const position
&, const position
*, int n
);
231 void simple_arc(const position
&, const position
&, const position
&);
232 void simple_circle(int, const position
&, double rad
);
233 void simple_ellipse(int, const position
&, const distance
&);
234 void simple_polygon(int, const position
*, int);
235 void line_thickness(double p
);
236 void set_fill(double);
237 void set_color(char *, char *);
239 char *get_last_filled();
240 char *get_outline_color();
241 position
transform(const position
&);
244 output
*make_troff_output()
246 return new troff_output
;
249 troff_output::troff_output()
250 : last_filename(0), last_line_thickness(BAD_THICKNESS
),
251 last_fill(-1.0), last_filled(0), last_outlined(0)
255 troff_output::~troff_output()
259 inline position
troff_output::transform(const position
&pos
)
261 return position((pos
.x
- upper_left
.x
)/scale
,
262 (upper_left
.y
- pos
.y
)/scale
);
265 #define FILL_REG "00"
267 // If this register > 0, then pic will generate \X'ps: ...' commands
268 // if the aligned attribute is used.
269 #define GROPS_REG "0p"
271 // If this register is defined, geqn won't produce `\x's.
272 #define EQN_NO_EXTRA_SPACE_REG "0x"
274 void troff_output::start_picture(double sc
,
275 const position
&ll
, const position
&ur
)
279 scale
= compute_scale(sc
, ll
, ur
);
280 height
= (ur
.y
- ll
.y
)/scale
;
281 double width
= (ur
.x
- ll
.x
)/scale
;
282 printf(".PS %.3fi %.3fi", height
, width
);
284 printf(" %s\n", args
);
287 printf(".\\\" %g %g %g %g\n", ll
.x
, ll
.y
, ur
.x
, ur
.y
);
288 printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height
, width
, 0.0);
289 printf(".nr " FILL_REG
" \\n(.u\n.nf\n");
290 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 1\n");
291 // This guarantees that if the picture is used in a diversion it will
292 // have the right width.
293 printf("\\h'%.3fi'\n.sp -1\n", width
);
296 void troff_output::finish_picture()
298 line_thickness(BAD_THICKNESS
);
299 last_fill
= -1.0; // force it to be reset for each picture
302 printf(".sp %.3fi+1\n", height
);
303 printf(".if \\n(" FILL_REG
" .fi\n");
305 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 0\n");
306 // this is a little gross
307 set_location(current_filename
, current_lineno
);
308 fputs(flyback_flag
? ".PF\n" : ".PE\n", stdout
);
311 void troff_output::command(const char *s
,
312 const char *filename
, int lineno
)
315 set_location(filename
, lineno
);
320 void troff_output::simple_circle(int filled
, const position
¢
, double rad
)
322 position c
= transform(cent
);
329 (filled
? 'C' : 'c'),
333 void troff_output::simple_ellipse(int filled
, const position
¢
,
336 position c
= transform(cent
);
341 c
.x
- dim
.x
/(2.0*scale
),
343 (filled
? 'E' : 'e'),
344 dim
.x
/scale
, dim
.y
/scale
);
347 void troff_output::simple_arc(const position
&start
, const distance
¢
,
350 position s
= transform(start
);
351 position c
= transform(cent
);
353 distance ev
= transform(end
) - c
;
356 "\\D'a%.3fi %.3fi %.3fi %.3fi'"
358 s
.x
, s
.y
, cv
.x
, cv
.y
, ev
.x
, ev
.y
);
361 void troff_output::simple_line(const position
&start
, const position
&end
)
363 position s
= transform(start
);
364 distance ev
= transform(end
) - s
;
369 s
.x
, s
.y
, ev
.x
, ev
.y
);
372 void troff_output::simple_spline(const position
&start
,
373 const position
*v
, int n
)
375 position pos
= transform(start
);
379 fputs("\\D'~", stdout
);
380 for (int i
= 0; i
< n
; i
++) {
381 position temp
= transform(v
[i
]);
382 distance d
= temp
- pos
;
386 printf("%.3fi %.3fi", d
.x
, d
.y
);
388 printf("'\n.sp -1\n");
393 void troff_output::simple_polygon(int filled
, const position
*v
, int n
)
395 position pos
= transform(v
[0]);
399 printf("\\D'%c", (filled
? 'P' : 'p'));
400 for (int i
= 1; i
< n
; i
++) {
401 position temp
= transform(v
[i
]);
402 distance d
= temp
- pos
;
406 printf("%.3fi %.3fi", d
.x
, d
.y
);
408 printf("'\n.sp -1\n");
411 const double TEXT_AXIS
= 0.22; // in ems
413 static const char *choose_delimiter(const char *text
)
415 if (strchr(text
, '\'') == 0)
421 void troff_output::text(const position
¢er
, text_piece
*v
, int n
,
424 line_thickness(BAD_THICKNESS
); // the text might use lines (eg in equations)
426 if (driver_extension_flag
&& ang
!= 0.0) {
428 position c
= transform(center
);
429 printf(".if \\n(" GROPS_REG
" \\{\\\n"
432 "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
435 c
.x
, c
.y
, -ang
*180.0/M_PI
);
437 for (int i
= 0; i
< n
; i
++)
438 if (v
[i
].text
!= 0 && *v
[i
].text
!= '\0') {
439 position c
= transform(center
);
440 if (v
[i
].filename
!= 0)
441 set_location(v
[i
].filename
, v
[i
].lineno
);
442 printf("\\h'%.3fi", c
.x
);
443 const char *delim
= choose_delimiter(v
[i
].text
);
444 if (v
[i
].adj
.h
== RIGHT_ADJUST
)
445 printf("-\\w%s%s%su", delim
, v
[i
].text
, delim
);
446 else if (v
[i
].adj
.h
!= LEFT_ADJUST
)
447 printf("-(\\w%s%s%su/2u)", delim
, v
[i
].text
, delim
);
449 printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
454 if (v
[i
].adj
.v
== ABOVE_ADJUST
)
456 else if (v
[i
].adj
.v
== BELOW_ADJUST
)
459 fputs(v
[i
].text
, stdout
);
460 fputs("\n.sp -1\n", stdout
);
463 printf(".if '\\*(.T'ps' \\{\\\n"
464 "\\X'ps: exec grestore'\n.sp -1\n"
468 void troff_output::line_thickness(double p
)
471 p
= RELATIVE_THICKNESS
;
472 if (driver_extension_flag
&& p
!= last_line_thickness
) {
473 printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p
, -p
);
474 last_line_thickness
= p
;
478 void troff_output::set_fill(double f
)
480 if (driver_extension_flag
&& f
!= last_fill
) {
481 printf("\\D'f %du'\n.sp -1\n", int(f
*FILL_MAX
));
487 printf("\\M[]\n.sp -1\n");
491 void troff_output::set_color(char *color_fill
, char *color_outlined
)
493 if (driver_extension_flag
) {
494 if (last_filled
|| last_outlined
) {
498 printf("\\M[%s]\n.sp -1\n", color_fill
);
499 last_filled
= strdup(color_fill
);
501 if (color_outlined
) {
502 printf("\\m[%s]\n.sp -1\n", color_outlined
);
503 last_outlined
= strdup(color_outlined
);
508 void troff_output::reset_color()
510 if (driver_extension_flag
) {
512 printf("\\M[]\n.sp -1\n");
517 printf("\\m[]\n.sp -1\n");
524 char *troff_output::get_last_filled()
529 char *troff_output::get_outline_color()
531 return last_outlined
;
534 const double DOT_AXIS
= .044;
536 void troff_output::dot(const position
¢
, const line_type
<
)
538 if (driver_extension_flag
) {
539 line_thickness(lt
.thickness
);
540 simple_line(cent
, cent
);
543 position c
= transform(cent
);
544 printf("\\h'%.3fi-(\\w'.'u/2u)'"
553 void troff_output::set_location(const char *s
, int n
)
555 if (last_filename
!= 0 && strcmp(s
, last_filename
) == 0)
556 printf(".lf %d\n", n
);
558 printf(".lf %d %s\n", n
, s
);