4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2005
5 Free Software Foundation, Inc.
6 Written by James Clark (jjc@jclark.com)
8 This file is part of groff.
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING. If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
28 const double RELATIVE_THICKNESS
= -1.0;
29 const double BAD_THICKNESS
= -2.0;
31 class simple_output
: public common_output
{
32 virtual void simple_line(const position
&, const position
&) = 0;
33 virtual void simple_spline(const position
&, const position
*, int n
) = 0;
34 virtual void simple_arc(const position
&, const position
&,
35 const position
&) = 0;
36 virtual void simple_circle(int, const position
&, double rad
) = 0;
37 virtual void simple_ellipse(int, const position
&, const distance
&) = 0;
38 virtual void simple_polygon(int, const position
*, int) = 0;
39 virtual void line_thickness(double) = 0;
40 virtual void set_fill(double) = 0;
41 virtual void set_color(char *, char *) = 0;
42 virtual void reset_color() = 0;
43 virtual char *get_last_filled() = 0;
44 void dot(const position
&, const line_type
&) = 0;
46 void start_picture(double sc
, const position
&ll
, const position
&ur
) = 0;
47 void finish_picture() = 0;
48 void text(const position
&, text_piece
*, int, double) = 0;
49 void line(const position
&, const position
*, int n
,
51 void polygon(const position
*, int n
,
52 const line_type
&, double);
53 void spline(const position
&, const position
*, int n
,
55 void arc(const position
&, const position
&, const position
&,
57 void circle(const position
&, double rad
, const line_type
&, double);
58 void ellipse(const position
&, const distance
&, const line_type
&, double);
59 int supports_filled_polygons();
62 int simple_output::supports_filled_polygons()
64 return driver_extension_flag
!= 0;
67 void simple_output::arc(const position
&start
, const position
¢
,
68 const position
&end
, const line_type
<
)
71 case line_type::solid
:
72 line_thickness(lt
.thickness
);
73 simple_arc(start
, cent
, end
);
75 case line_type::invisible
:
77 case line_type::dashed
:
78 dashed_arc(start
, cent
, end
, lt
);
80 case line_type::dotted
:
81 dotted_arc(start
, cent
, end
, lt
);
86 void simple_output::line(const position
&start
, const position
*v
, int n
,
90 line_thickness(lt
.thickness
);
91 for (int i
= 0; i
< n
; i
++) {
93 case line_type::solid
:
94 simple_line(pos
, v
[i
]);
96 case line_type::dotted
:
98 distance
vec(v
[i
] - pos
);
99 double dist
= hypot(vec
);
100 int ndots
= int(dist
/lt
.dash_width
+ .5);
104 vec
/= double(ndots
);
105 for (int j
= 0; j
<= ndots
; j
++)
106 dot(pos
+ vec
*j
, lt
);
110 case line_type::dashed
:
112 distance
vec(v
[i
] - pos
);
113 double dist
= hypot(vec
);
114 if (dist
<= lt
.dash_width
*2.0)
115 simple_line(pos
, v
[i
]);
117 int ndashes
= int((dist
- lt
.dash_width
)/(lt
.dash_width
*2.0) + .5);
118 distance dash_vec
= vec
*(lt
.dash_width
/dist
);
119 double dash_gap
= (dist
- lt
.dash_width
)/ndashes
;
120 distance dash_gap_vec
= vec
*(dash_gap
/dist
);
121 for (int j
= 0; j
<= ndashes
; j
++) {
122 position
s(pos
+ dash_gap_vec
*j
);
123 simple_line(s
, s
+ dash_vec
);
128 case line_type::invisible
:
137 void simple_output::spline(const position
&start
, const position
*v
, int n
,
140 line_thickness(lt
.thickness
);
141 simple_spline(start
, v
, n
);
144 void simple_output::polygon(const position
*v
, int n
,
145 const line_type
<
, double fill
)
147 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
148 if (get_last_filled() == 0)
150 simple_polygon(1, v
, n
);
152 if (lt
.type
== line_type::solid
&& driver_extension_flag
) {
153 line_thickness(lt
.thickness
);
154 simple_polygon(0, v
, n
);
156 else if (lt
.type
!= line_type::invisible
) {
157 line_thickness(lt
.thickness
);
158 line(v
[n
- 1], v
, n
, lt
);
162 void simple_output::circle(const position
¢
, double rad
,
163 const line_type
<
, double fill
)
165 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
166 if (get_last_filled() == 0)
168 simple_circle(1, cent
, rad
);
170 line_thickness(lt
.thickness
);
172 case line_type::invisible
:
174 case line_type::dashed
:
175 dashed_circle(cent
, rad
, lt
);
177 case line_type::dotted
:
178 dotted_circle(cent
, rad
, lt
);
180 case line_type::solid
:
181 simple_circle(0, cent
, rad
);
188 void simple_output::ellipse(const position
¢
, const distance
&dim
,
189 const line_type
<
, double fill
)
191 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
192 if (get_last_filled() == 0)
194 simple_ellipse(1, cent
, dim
);
196 if (lt
.type
!= line_type::invisible
)
197 line_thickness(lt
.thickness
);
199 case line_type::invisible
:
201 case line_type::dotted
:
202 dotted_ellipse(cent
, dim
, lt
);
204 case line_type::dashed
:
205 dashed_ellipse(cent
, dim
, lt
);
207 case line_type::solid
:
208 simple_ellipse(0, cent
, dim
);
215 class troff_output
: public simple_output
{
216 const char *last_filename
;
220 double last_line_thickness
;
222 char *last_filled
; // color
223 char *last_outlined
; // color
227 void start_picture(double, const position
&ll
, const position
&ur
);
228 void finish_picture();
229 void text(const position
&, text_piece
*, int, double);
230 void dot(const position
&, const line_type
&);
231 void command(const char *, const char *, int);
232 void set_location(const char *, int);
233 void simple_line(const position
&, const position
&);
234 void simple_spline(const position
&, const position
*, int n
);
235 void simple_arc(const position
&, const position
&, const position
&);
236 void simple_circle(int, const position
&, double rad
);
237 void simple_ellipse(int, const position
&, const distance
&);
238 void simple_polygon(int, const position
*, int);
239 void line_thickness(double p
);
240 void set_fill(double);
241 void set_color(char *, char *);
243 char *get_last_filled();
244 char *get_outline_color();
245 position
transform(const position
&);
248 output
*make_troff_output()
250 return new troff_output
;
253 troff_output::troff_output()
254 : last_filename(0), last_line_thickness(BAD_THICKNESS
),
255 last_fill(-1.0), last_filled(0), last_outlined(0)
259 troff_output::~troff_output()
263 inline position
troff_output::transform(const position
&pos
)
265 return position((pos
.x
- upper_left
.x
)/scale
,
266 (upper_left
.y
- pos
.y
)/scale
);
269 #define FILL_REG "00"
271 // If this register > 0, then pic will generate \X'ps: ...' commands
272 // if the aligned attribute is used.
273 #define GROPS_REG "0p"
275 // If this register is defined, geqn won't produce `\x's.
276 #define EQN_NO_EXTRA_SPACE_REG "0x"
278 void troff_output::start_picture(double sc
,
279 const position
&ll
, const position
&ur
)
283 scale
= compute_scale(sc
, ll
, ur
);
284 height
= (ur
.y
- ll
.y
)/scale
;
285 double width
= (ur
.x
- ll
.x
)/scale
;
286 printf(".PS %.3fi %.3fi", height
, width
);
288 printf(" %s\n", args
);
291 printf(".\\\" %g %g %g %g\n", ll
.x
, ll
.y
, ur
.x
, ur
.y
);
292 printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height
, width
, 0.0);
293 printf(".nr " FILL_REG
" \\n(.u\n.nf\n");
294 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 1\n");
295 // This guarantees that if the picture is used in a diversion it will
296 // have the right width.
297 printf("\\h'%.3fi'\n.sp -1\n", width
);
300 void troff_output::finish_picture()
302 line_thickness(BAD_THICKNESS
);
303 last_fill
= -1.0; // force it to be reset for each picture
306 printf(".sp %.3fi+1\n", height
);
307 printf(".if \\n(" FILL_REG
" .fi\n");
309 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 0\n");
310 // this is a little gross
311 set_location(current_filename
, current_lineno
);
312 fputs(flyback_flag
? ".PF\n" : ".PE\n", stdout
);
315 void troff_output::command(const char *s
,
316 const char *filename
, int lineno
)
319 set_location(filename
, lineno
);
324 void troff_output::simple_circle(int filled
, const position
¢
, double rad
)
326 position c
= transform(cent
);
333 (filled
? 'C' : 'c'),
337 void troff_output::simple_ellipse(int filled
, const position
¢
,
340 position c
= transform(cent
);
343 "\\D'%c %.3fi %.3fi'"
345 c
.x
- dim
.x
/(2.0*scale
),
347 (filled
? 'E' : 'e'),
348 dim
.x
/scale
, dim
.y
/scale
);
351 void troff_output::simple_arc(const position
&start
, const distance
¢
,
354 position s
= transform(start
);
355 position c
= transform(cent
);
357 distance ev
= transform(end
) - c
;
360 "\\D'a %.3fi %.3fi %.3fi %.3fi'"
362 s
.x
, s
.y
, cv
.x
, cv
.y
, ev
.x
, ev
.y
);
365 void troff_output::simple_line(const position
&start
, const position
&end
)
367 position s
= transform(start
);
368 distance ev
= transform(end
) - s
;
373 s
.x
, s
.y
, ev
.x
, ev
.y
);
376 void troff_output::simple_spline(const position
&start
,
377 const position
*v
, int n
)
379 position pos
= transform(start
);
383 fputs("\\D'~ ", stdout
);
384 for (int i
= 0; i
< n
; i
++) {
385 position temp
= transform(v
[i
]);
386 distance d
= temp
- pos
;
390 printf("%.3fi %.3fi", d
.x
, d
.y
);
392 printf("'\n.sp -1\n");
397 void troff_output::simple_polygon(int filled
, const position
*v
, int n
)
399 position pos
= transform(v
[0]);
403 printf("\\D'%c ", (filled
? 'P' : 'p'));
404 for (int i
= 1; i
< n
; i
++) {
405 position temp
= transform(v
[i
]);
406 distance d
= temp
- pos
;
410 printf("%.3fi %.3fi", d
.x
, d
.y
);
412 printf("'\n.sp -1\n");
415 const double TEXT_AXIS
= 0.22; // in ems
417 static const char *choose_delimiter(const char *text
)
419 if (strchr(text
, '\'') == 0)
425 void troff_output::text(const position
¢er
, text_piece
*v
, int n
,
428 line_thickness(BAD_THICKNESS
); // the text might use lines (eg in equations)
430 if (driver_extension_flag
&& ang
!= 0.0) {
432 position c
= transform(center
);
433 printf(".if \\n(" GROPS_REG
" \\{\\\n"
436 "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
439 c
.x
, c
.y
, -ang
*180.0/M_PI
);
441 for (int i
= 0; i
< n
; i
++)
442 if (v
[i
].text
!= 0 && *v
[i
].text
!= '\0') {
443 position c
= transform(center
);
444 if (v
[i
].filename
!= 0)
445 set_location(v
[i
].filename
, v
[i
].lineno
);
446 printf("\\h'%.3fi", c
.x
);
447 const char *delim
= choose_delimiter(v
[i
].text
);
448 if (v
[i
].adj
.h
== RIGHT_ADJUST
)
449 printf("-\\w%s%s%su", delim
, v
[i
].text
, delim
);
450 else if (v
[i
].adj
.h
!= LEFT_ADJUST
)
451 printf("-(\\w%s%s%su/2u)", delim
, v
[i
].text
, delim
);
453 printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
458 if (v
[i
].adj
.v
== ABOVE_ADJUST
)
460 else if (v
[i
].adj
.v
== BELOW_ADJUST
)
463 fputs(v
[i
].text
, stdout
);
464 fputs("\n.sp -1\n", stdout
);
467 printf(".if '\\*(.T'ps' \\{\\\n"
468 "\\X'ps: exec grestore'\n.sp -1\n"
472 void troff_output::line_thickness(double p
)
475 p
= RELATIVE_THICKNESS
;
476 if (driver_extension_flag
&& p
!= last_line_thickness
) {
477 printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p
, -p
);
478 last_line_thickness
= p
;
482 void troff_output::set_fill(double f
)
484 if (driver_extension_flag
&& f
!= last_fill
) {
485 // \D'Fg ...' emits a node only in compatibility mode,
486 // thus we add a dummy node
487 printf("\\&\\D'Fg %.3f'\n.sp -1\n", 1.0 - f
);
497 void troff_output::set_color(char *color_fill
, char *color_outlined
)
499 if (driver_extension_flag
) {
500 if (last_filled
|| last_outlined
) {
503 // .gcolor and .fcolor emit a node in compatibility mode only,
504 // but that won't work anyway
506 printf(".fcolor %s\n", color_fill
);
507 last_filled
= strsave(color_fill
);
509 if (color_outlined
) {
510 printf(".gcolor %s\n", color_outlined
);
511 last_outlined
= strsave(color_outlined
);
516 void troff_output::reset_color()
518 if (driver_extension_flag
) {
521 a_delete last_filled
;
526 a_delete last_outlined
;
532 char *troff_output::get_last_filled()
537 char *troff_output::get_outline_color()
539 return last_outlined
;
542 const double DOT_AXIS
= .044;
544 void troff_output::dot(const position
¢
, const line_type
<
)
546 if (driver_extension_flag
) {
547 line_thickness(lt
.thickness
);
548 simple_line(cent
, cent
);
551 position c
= transform(cent
);
552 printf("\\h'%.3fi-(\\w'.'u/2u)'"
561 void troff_output::set_location(const char *s
, int n
)
563 if (last_filename
!= 0 && strcmp(s
, last_filename
) == 0)
564 printf(".lf %d\n", n
);
566 printf(".lf %d %s\n", n
, s
);