2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2005
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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, 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 dotted_ellipse(cent
, dim
, lt
);
202 case line_type::dashed
:
203 dashed_ellipse(cent
, dim
, lt
);
205 case line_type::solid
:
206 simple_ellipse(0, cent
, dim
);
213 class troff_output
: public simple_output
{
214 const char *last_filename
;
218 double last_line_thickness
;
220 char *last_filled
; // color
221 char *last_outlined
; // color
225 void start_picture(double, const position
&ll
, const position
&ur
);
226 void finish_picture();
227 void text(const position
&, text_piece
*, int, double);
228 void dot(const position
&, const line_type
&);
229 void command(const char *, const char *, int);
230 void set_location(const char *, int);
231 void simple_line(const position
&, const position
&);
232 void simple_spline(const position
&, const position
*, int n
);
233 void simple_arc(const position
&, const position
&, const position
&);
234 void simple_circle(int, const position
&, double rad
);
235 void simple_ellipse(int, const position
&, const distance
&);
236 void simple_polygon(int, const position
*, int);
237 void line_thickness(double p
);
238 void set_fill(double);
239 void set_color(char *, char *);
241 char *get_last_filled();
242 char *get_outline_color();
243 position
transform(const position
&);
246 output
*make_troff_output()
248 return new troff_output
;
251 troff_output::troff_output()
252 : last_filename(0), last_line_thickness(BAD_THICKNESS
),
253 last_fill(-1.0), last_filled(0), last_outlined(0)
257 troff_output::~troff_output()
261 inline position
troff_output::transform(const position
&pos
)
263 return position((pos
.x
- upper_left
.x
)/scale
,
264 (upper_left
.y
- pos
.y
)/scale
);
267 #define FILL_REG "00"
269 // If this register > 0, then pic will generate \X'ps: ...' commands
270 // if the aligned attribute is used.
271 #define GROPS_REG "0p"
273 // If this register is defined, geqn won't produce `\x's.
274 #define EQN_NO_EXTRA_SPACE_REG "0x"
276 void troff_output::start_picture(double sc
,
277 const position
&ll
, const position
&ur
)
281 scale
= compute_scale(sc
, ll
, ur
);
282 height
= (ur
.y
- ll
.y
)/scale
;
283 double width
= (ur
.x
- ll
.x
)/scale
;
284 printf(".PS %.3fi %.3fi", height
, width
);
286 printf(" %s\n", args
);
289 printf(".\\\" %g %g %g %g\n", ll
.x
, ll
.y
, ur
.x
, ur
.y
);
290 printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height
, width
, 0.0);
291 printf(".nr " FILL_REG
" \\n(.u\n.nf\n");
292 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 1\n");
293 // This guarantees that if the picture is used in a diversion it will
294 // have the right width.
295 printf("\\h'%.3fi'\n.sp -1\n", width
);
298 void troff_output::finish_picture()
300 line_thickness(BAD_THICKNESS
);
301 last_fill
= -1.0; // force it to be reset for each picture
304 printf(".sp %.3fi+1\n", height
);
305 printf(".if \\n(" FILL_REG
" .fi\n");
307 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 0\n");
308 // this is a little gross
309 set_location(current_filename
, current_lineno
);
310 fputs(flyback_flag
? ".PF\n" : ".PE\n", stdout
);
313 void troff_output::command(const char *s
,
314 const char *filename
, int lineno
)
317 set_location(filename
, lineno
);
322 void troff_output::simple_circle(int filled
, const position
¢
, double rad
)
324 position c
= transform(cent
);
331 (filled
? 'C' : 'c'),
335 void troff_output::simple_ellipse(int filled
, const position
¢
,
338 position c
= transform(cent
);
341 "\\D'%c %.3fi %.3fi'"
343 c
.x
- dim
.x
/(2.0*scale
),
345 (filled
? 'E' : 'e'),
346 dim
.x
/scale
, dim
.y
/scale
);
349 void troff_output::simple_arc(const position
&start
, const distance
¢
,
352 position s
= transform(start
);
353 position c
= transform(cent
);
355 distance ev
= transform(end
) - c
;
358 "\\D'a %.3fi %.3fi %.3fi %.3fi'"
360 s
.x
, s
.y
, cv
.x
, cv
.y
, ev
.x
, ev
.y
);
363 void troff_output::simple_line(const position
&start
, const position
&end
)
365 position s
= transform(start
);
366 distance ev
= transform(end
) - s
;
371 s
.x
, s
.y
, ev
.x
, ev
.y
);
374 void troff_output::simple_spline(const position
&start
,
375 const position
*v
, int n
)
377 position pos
= transform(start
);
381 fputs("\\D'~ ", stdout
);
382 for (int i
= 0; i
< n
; i
++) {
383 position temp
= transform(v
[i
]);
384 distance d
= temp
- pos
;
388 printf("%.3fi %.3fi", d
.x
, d
.y
);
390 printf("'\n.sp -1\n");
395 void troff_output::simple_polygon(int filled
, const position
*v
, int n
)
397 position pos
= transform(v
[0]);
401 printf("\\D'%c ", (filled
? 'P' : 'p'));
402 for (int i
= 1; i
< n
; i
++) {
403 position temp
= transform(v
[i
]);
404 distance d
= temp
- pos
;
408 printf("%.3fi %.3fi", d
.x
, d
.y
);
410 printf("'\n.sp -1\n");
413 const double TEXT_AXIS
= 0.22; // in ems
415 static const char *choose_delimiter(const char *text
)
417 if (strchr(text
, '\'') == 0)
423 void troff_output::text(const position
¢er
, text_piece
*v
, int n
,
426 line_thickness(BAD_THICKNESS
); // the text might use lines (eg in equations)
428 if (driver_extension_flag
&& ang
!= 0.0) {
430 position c
= transform(center
);
431 printf(".if \\n(" GROPS_REG
" \\{\\\n"
434 "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
437 c
.x
, c
.y
, -ang
*180.0/M_PI
);
439 for (int i
= 0; i
< n
; i
++)
440 if (v
[i
].text
!= 0 && *v
[i
].text
!= '\0') {
441 position c
= transform(center
);
442 if (v
[i
].filename
!= 0)
443 set_location(v
[i
].filename
, v
[i
].lineno
);
444 printf("\\h'%.3fi", c
.x
);
445 const char *delim
= choose_delimiter(v
[i
].text
);
446 if (v
[i
].adj
.h
== RIGHT_ADJUST
)
447 printf("-\\w%s%s%su", delim
, v
[i
].text
, delim
);
448 else if (v
[i
].adj
.h
!= LEFT_ADJUST
)
449 printf("-(\\w%s%s%su/2u)", delim
, v
[i
].text
, delim
);
451 printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
456 if (v
[i
].adj
.v
== ABOVE_ADJUST
)
458 else if (v
[i
].adj
.v
== BELOW_ADJUST
)
461 fputs(v
[i
].text
, stdout
);
462 fputs("\n.sp -1\n", stdout
);
465 printf(".if '\\*(.T'ps' \\{\\\n"
466 "\\X'ps: exec grestore'\n.sp -1\n"
470 void troff_output::line_thickness(double p
)
473 p
= RELATIVE_THICKNESS
;
474 if (driver_extension_flag
&& p
!= last_line_thickness
) {
475 printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p
, -p
);
476 last_line_thickness
= p
;
480 void troff_output::set_fill(double f
)
482 if (driver_extension_flag
&& f
!= last_fill
) {
483 // \D'Fg ...' emits a node only in compatibility mode,
484 // thus we add a dummy node
485 printf("\\&\\D'Fg %.3f'\n.sp -1\n", 1.0 - f
);
495 void troff_output::set_color(char *color_fill
, char *color_outlined
)
497 if (driver_extension_flag
) {
498 if (last_filled
|| last_outlined
) {
501 // .gcolor and .fcolor emit a node in compatibility mode only,
502 // but that won't work anyway
504 printf(".fcolor %s\n", color_fill
);
505 last_filled
= strsave(color_fill
);
507 if (color_outlined
) {
508 printf(".gcolor %s\n", color_outlined
);
509 last_outlined
= strsave(color_outlined
);
514 void troff_output::reset_color()
516 if (driver_extension_flag
) {
519 a_delete last_filled
;
524 a_delete last_outlined
;
530 char *troff_output::get_last_filled()
535 char *troff_output::get_outline_color()
537 return last_outlined
;
540 const double DOT_AXIS
= .044;
542 void troff_output::dot(const position
¢
, const line_type
<
)
544 if (driver_extension_flag
) {
545 line_thickness(lt
.thickness
);
546 simple_line(cent
, cent
);
549 position c
= transform(cent
);
550 printf("\\h'%.3fi-(\\w'.'u/2u)'"
559 void troff_output::set_location(const char *s
, int n
)
561 if (last_filename
!= 0 && strcmp(s
, last_filename
) == 0)
562 printf(".lf %d\n", n
);
564 printf(".lf %d %s\n", n
, s
);